理解并合理運(yùn)用Spring Boot配置加載的優(yōu)先級(jí),對(duì)于保障應(yīng)用的安全性、可維護(hù)性以及降低部署復(fù)雜度至關(guān)重要。特別是在大規(guī)模微服務(wù)架構(gòu)中,合理的配置管理和遷移對(duì)于整體系統(tǒng)的穩(wěn)定性有著不可忽視的作用。
Spring Boot作為一種輕量級(jí)的Java應(yīng)用程序框架,以其開(kāi)箱即用、快速搭建新項(xiàng)目的特性贏得了廣大開(kāi)發(fā)者的青睞。其核心理念之一就是簡(jiǎn)化配置過(guò)程,使開(kāi)發(fā)者能夠快速響應(yīng)復(fù)雜多變的生產(chǎn)環(huán)境需求。為了實(shí)現(xiàn)這一點(diǎn),Spring Boot支持豐富的外部化配置機(jī)制,允許應(yīng)用程序根據(jù)不同的部署環(huán)境靈活加載相應(yīng)的配置屬性,而無(wú)需修改代碼本身。
在Spring Boot生態(tài)系統(tǒng)中,配置屬性可以從各種來(lái)源獲取,比如:Java屬性文件、YAML文件、環(huán)境變量、命令行參數(shù)等。這些配置屬性能夠在運(yùn)行時(shí)動(dòng)態(tài)注入到Bean中,極大地提高了系統(tǒng)的可擴(kuò)展性和可配置性。然而,為了確保一致性和防止配置沖突,Spring Boot在加載這些外部配置時(shí)遵循一套嚴(yán)格的優(yōu)先級(jí)順序。掌握這套優(yōu)先級(jí)規(guī)則至關(guān)重要,因?yàn)樗苯佑绊懼罱K生效的配置屬性值,進(jìn)而決定了應(yīng)用程序的行為模式。
本文將深入探討Spring Boot加載外部配置屬性的優(yōu)先級(jí)規(guī)則,詳盡梳理各個(gè)配置源的加載順序,并結(jié)合實(shí)際應(yīng)用場(chǎng)景舉例說(shuō)明,以便我們能夠更高效地管理和遷移配置,確保在不同環(huán)境下應(yīng)用程序都能穩(wěn)定、準(zhǔn)確地運(yùn)行。
Spring Boot的核心價(jià)值之一在于其強(qiáng)大的外部化配置能力,這使得應(yīng)用程序能夠在不改變代碼的情況下適應(yīng)不同的運(yùn)行環(huán)境。外部化配置意味著將應(yīng)用程序的關(guān)鍵配置信息移至應(yīng)用程序代碼之外,便于根據(jù)不同環(huán)境(如開(kāi)發(fā)、測(cè)試、生產(chǎn)等)進(jìn)行定制化配置。Spring Boot提供了多樣化的外部配置源以及便捷的屬性注入方式,使得這種配置機(jī)制變得異常靈活且易于管理。
Spring Boot支持多種類型的外部配置源,主要有如下幾個(gè)方面:
.properties
格式,采用鍵值對(duì)的形式存儲(chǔ)配置信息。
server.port=8080
logging.level.root=DEBUG
.yml
格式。
server:
port: 8080
logging:
level:
root: DEBUG
環(huán)境變量
:
操作系統(tǒng)級(jí)別的環(huán)境變量可以被Spring Boot識(shí)別并作為配置源,這對(duì)于云環(huán)境和容器化部署尤為實(shí)用。
命令行參數(shù)
:
啟動(dòng)Spring Boot應(yīng)用時(shí),可以傳入命令行參數(shù)(以
--
開(kāi)頭)直接覆蓋已有配置。
在Spring Boot中,外部配置的屬性值可以通過(guò)以下幾種方式方便地注入到Bean中。
@Value
注解
:可以直接在字段或方法參數(shù)上使用此注解,將配置屬性值注入到目標(biāo)對(duì)象中。
Environment
接口
:Spring框架提供的環(huán)境抽象類,可以用來(lái)查詢所有已加載的配置信息。
@ConfigurationProperties
注解
:用于綁定一組相關(guān)配置到一個(gè)專門的Java Bean中,提供更結(jié)構(gòu)化的配置管理方式。
Spring Boot對(duì)來(lái)自不同配置源的同名屬性可以按照一定的優(yōu)先級(jí)順序進(jìn)行覆蓋。其優(yōu)先級(jí)從上到下變高,即后面的配置源將覆蓋前面的配置源。
SpringApplication.setDefaultProperties
方法設(shè)置)
@PropertySource
注解加載的配置
@SpringBootTest
、
@DynamicPropertySource
和
@TestPropertySource
)
以上優(yōu)先級(jí)順序來(lái)源于官網(wǎng): Spring Boot Reference Documentation
默認(rèn)屬性是指Spring Boot框架內(nèi)置的一些默認(rèn)配置值。可以在創(chuàng)建
SpringApplication
實(shí)例時(shí),通過(guò)調(diào)用
setDefaultProperties(Map
方法來(lái)提供一組默認(rèn)屬性,這些屬性將被優(yōu)先加載,但是也會(huì)被其他配置覆蓋。
@SpringBootApplication
public class SpringBootBaseApplication {
public static void main(String[] args) {
Map defaultProperties = new HashMap<>();
defaultProperties.put("server.port", "9000"); // 自定義默認(rèn)端口
SpringApplication app = new SpringApplication(SpringBootBaseApplication.class);
app.setDefaultProperties(defaultProperties);
app.run(args);
}
}
@PropertySource
注解用于在Spring Boot的
@Configuration
類上加載外部屬性文件。當(dāng)我們?cè)谂渲妙惿鲜褂?
@PropertySource
時(shí),需要注意的是,這些屬性源并不會(huì)立即被添加到Spring的
Environment
中。它們是在Spring應(yīng)用上下文刷新(refresh)階段才會(huì)被真正加載并合并到環(huán)境變量中。
有興趣的可以跟一下源碼,
org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
中執(zhí)行的。
Spring Boot的主引導(dǎo)配置,如服務(wù)器端口(server.port)、日志框架的初始化(例如日志級(jí)別設(shè)置)等,也是在應(yīng)用上下文刷新之前就被讀取并應(yīng)用的。因此,對(duì)于這類早期就需要讀取的配置,應(yīng)該直接在
application.properties
或者環(huán)境變量等更早被加載的配置源中進(jìn)行設(shè)置。
我們創(chuàng)建一個(gè)
propertysource.properties
文件:
server.port = 9001
coderacademy.name = CoderAcademy
然后我們?cè)?
@Configuration
配置上使用
@PropertySource
導(dǎo)入
propertysource.properties
文件。
@PropertySource(value = "classpath:propertysource.properties")
@Configuration
public class MyConfig {
}
我們?cè)趹?yīng)用啟動(dòng)后看一下上述配置:
@SpringBootApplication
public class SpringBootBaseApplication {
public static void main(String[] args) {
Map defaultProperties = new HashMap<>();
defaultProperties.put("server.port", "9000"); // 自定義默認(rèn)端口
SpringApplication app = new SpringApplication(SpringBootBaseApplication.class);
app.setDefaultProperties(defaultProperties);
ConfigurableApplicationContext context = app.run(args);
Environment environment = context.getEnvironment();
System.out.println("coderacademy.name: " + environment.getProperty("coderacademy.name"));
}
}
打印結(jié)果:
可以看出
server.port
變成了9001,即
@PropertySource
加載的配置覆蓋了
SpringBoot
默認(rèn)的屬性值。
Config Data(配置數(shù)據(jù))是Spring Boot中用于外部化應(yīng)用配置的核心部分。主要由內(nèi)部配置文件以及外部配置文件。
內(nèi)部配置文件最基礎(chǔ)的應(yīng)用配置文件,位于項(xiàng)目構(gòu)建后的jar包內(nèi)部。位于
src/main/resource
目錄下的文件。
可以將配置文件放在jar包外面的某個(gè)路徑下。這種方式有助于在不修改jar包的情況下變更配置。比如我們使用的配置中心(
nacos
,
apollo
等),也可以通過(guò)
spring.config.location
或者
spring.config.additional-location
指定的文件等。
SpringBoot在啟動(dòng)時(shí)會(huì)默認(rèn)從特定的目錄中加載這些配置文件。我們可以從
ConfigDataEnvironment
中找到這些目錄:
其目錄的加載順序由低到高為:
file:./
file:./config/
file:./config/*/
classpath:/
classpath:/config/
其中
file
代表應(yīng)用根目錄下的文件,而
classpath
為
resources
下的文件。
這些配置文件的配置優(yōu)先級(jí)順序由低到高為:
classpath:/
classpath:/config/
file:./
file:./config/
file:./config/*/
本例基于SpringBoot2.7版本。
關(guān)于SpringBoot加載內(nèi)部配置文件的執(zhí)行流程以及原理,請(qǐng)參考:
華為二面:SpringBoot讀取_配置文件_的原理是什么?加載順序是什么?
我們分別在這些目錄下創(chuàng)建配置文件
application.properties
:
我們?cè)趯?duì)應(yīng)文件中寫入他們的目錄路徑:
1: config.data.path = classpath:./
2: config.data.path = classpath:./config/
3: config.data.path = file:./
4: config.data.path = file:./config/
5: config.data.path = file:./config/dev
我們?cè)赟pringBoot啟動(dòng)時(shí)打印
config.data.path
的值:
@SpringBootApplication
public class SpringBootConfigApplication {
public static void main(String[] args) {
Map defaultProperties = new HashMap<>();
defaultProperties.put("server.port", "9000"); // 自定義默認(rèn)端口
SpringApplication app = new SpringApplication(SpringBootConfigApplication.class);
app.setDefaultProperties(defaultProperties);
ConfigurableApplicationContext context = app.run(args);
Environment environment = context.getEnvironment();
System.out.println("config.data.path: " + environment.getProperty("config.data.path"));
}
}
我們分步進(jìn)行驗(yàn)證,先驗(yàn)證1,2,打印結(jié)果:
config.data.path: classpath:./config/
繼續(xù)驗(yàn)證1,2,3,打印結(jié)果:
config.data.path: file:./
驗(yàn)證1,2,3,4,打印結(jié)果:
config.data.path: file:./config/
驗(yàn)證1,2,3,4,5,打印結(jié)果:
config.data.path: file:./config/dev
RandomValuePropertySource
在Spring Boot中,
RandomValuePropertySource
是一個(gè)特殊屬性源,它并不來(lái)源于固定的配置文件或環(huán)境變量,而是由Spring Boot框架在啟動(dòng)時(shí)自動(dòng)添加。這個(gè)屬性源提供的屬性名以
random.*
開(kāi)頭,可以用于生成隨機(jī)值。例如,你可以在配置文件中引用
random.int
或
random.long
等屬性,Spring Boot在啟動(dòng)時(shí)會(huì)為這些屬性生成隨機(jī)整數(shù)值。這對(duì)于需要在運(yùn)行時(shí)生成一些臨時(shí)或隨機(jī)值的場(chǎng)景非常有用,如臨時(shí)密碼、緩存密鑰等。
比如我們?cè)?
application.properties
中設(shè)置
random.int=100
random.int=100
我們?cè)赟pringBoot啟動(dòng)時(shí)獲取``random.int`的值:
@SpringBootApplication
public class ConfigApplication
{
public static void main( String[] args )
{
SpringApplication app = new SpringApplication(ConfigApplication.class);
ConfigurableApplicationContext context = app.run(args);
Environment environment = context.getEnvironment();
System.out.println("random.int: " + environment.getProperty("random.int"));
}
}
打印結(jié)果為:
random.int: -510589238
并且每次重新啟動(dòng)應(yīng)用,打印的結(jié)果都不一樣。
在Spring Boot中,環(huán)境變量可以用作配置源,Spring Boot會(huì)自動(dòng)檢測(cè)并加載這些環(huán)境變量作為應(yīng)用的配置屬性。例如,如果在操作系統(tǒng)中設(shè)置了環(huán)境變量
MY_APP_PORT=8080
,那么在Spring Boot應(yīng)用中可以通過(guò)
${MY_APP_PORT}
來(lái)引用這個(gè)值。
我們?cè)O(shè)置環(huán)境變量為
config.data.path=環(huán)境變量
:
我們啟動(dòng)引用,依然打印
config.data.path
的結(jié)果為:
config.data.path: 環(huán)境變量
Java系統(tǒng)屬性是通過(guò)
System.setProperty()
方法設(shè)置一系列鍵值對(duì)。
@SpringBootApplication
public class ConfigApplication
{
static {
System.setProperty("config.data.path", "SystemProperty"); // 設(shè)置系統(tǒng)屬性
}
public static void main( String[] args )
{
SpringApplication app = new SpringApplication(ConfigApplication.class);
ConfigurableApplicationContext context = app.run(args);
Environment environment = context.getEnvironment();
System.out.println("config.data.path: " + environment.getProperty("config.data.path"));
}
}
打印結(jié)果為:
config.data.path: SystemProperty
SPRING_APPLICATION_JSON
是 Spring Boot 提供的一種機(jī)制,允許通過(guò)環(huán)境變量傳遞 JSON 格式的配置給應(yīng)用程序。這個(gè)環(huán)境變量的內(nèi)容會(huì)被解析成一個(gè) JSON 對(duì)象,并合并到Spring的
Environment
中,就像其他屬性源一樣。
@SpringBootApplication
public class ConfigApplication
{
static {
System.setProperty("config.data.path", "SystemProperty"); // 設(shè)置系統(tǒng)屬性
System.setProperty("SPRING_APPLICATION_JSON", "{\"config.data.path\":\"SPRING_APPLICATION_JSON環(huán)境變量中的內(nèi)嵌JSON屬性\"}");
}
public static void main( String[] args )
{
SpringApplication app = new SpringApplication(ConfigApplication.class);
ConfigurableApplicationContext context = app.run(args);
Environment environment = context.getEnvironment();
System.out.println("config.data.path: " + environment.getProperty("config.data.path"));
}
}
打印結(jié)果:
config.data.path: SPRING_APPLICATION_JSON環(huán)境變量中的內(nèi)嵌JSON屬性
啟動(dòng)Spring Boot應(yīng)用時(shí),可以直接通過(guò)命令行參數(shù)來(lái)覆蓋或設(shè)置配置屬性。命令行參數(shù)通常以
--
開(kāi)頭,后面緊跟屬性名和值,如
--server.port=8080
。這種方式可以在不修改配置文件的前提下臨時(shí)調(diào)整應(yīng)用配置。命令行參數(shù)具有較高的優(yōu)先級(jí),可以覆蓋其它配置源中的屬性值。
我們使用
java -jar
啟動(dòng)SpringBoot:
java -jar ./springboot-config-1.0-SNAPSHOT.jar --config.data.path=命令行參數(shù)
打印結(jié)果為:
config.data.path: 命令行參數(shù)
關(guān)于SpringBoot的jar包,可以通過(guò)java -jar命令直接執(zhí)行的原因請(qǐng)參考: 字節(jié)二面:為什么SpringBoot的?jar?可以直接運(yùn)行?我說(shuō)內(nèi)嵌了Tomcat容器,他讓我出門左轉(zhuǎn)
至于其他的跟單測(cè)有關(guān)的配置,我們就不一一細(xì)說(shuō)了
Spring Boot配置加載優(yōu)先級(jí)的設(shè)計(jì)具有深遠(yuǎn)的實(shí)際意義和重要性。這一機(jī)制確保了應(yīng)用在不同環(huán)境和部署場(chǎng)景下的高度靈活性和可移植性,同時(shí)也極大提升了開(kāi)發(fā)和運(yùn)維團(tuán)隊(duì)的生產(chǎn)力和協(xié)同效率。
優(yōu)先級(jí)順序的嚴(yán)謹(jǐn)性使得開(kāi)發(fā)者能夠精細(xì)地控制配置的覆蓋層級(jí),從而使同一份代碼可以根據(jù)不同環(huán)境的需求加載不同的配置屬性。例如,在開(kāi)發(fā)、測(cè)試和生產(chǎn)環(huán)境中分別啟用不同的數(shù)據(jù)庫(kù)連接、日志級(jí)別或API密鑰等敏感信息,而無(wú)需在代碼中硬編碼。
Spring Boot的配置加載流程首先考慮了默認(rèn)配置,然后逐步加載用戶通過(guò)
@PropertySource
注解引入的屬性源、打包在jar包內(nèi)外的各種application.properties和application-{profile}.properties或YAML文件、環(huán)境變量、系統(tǒng)屬性,直至命令行參數(shù)等。這種分層加載策略確保了越靠后的配置源擁有更高的優(yōu)先級(jí),從而可以覆蓋之前的配置,這也體現(xiàn)了配置的靈活性和即時(shí)性。
理解并合理運(yùn)用Spring Boot配置加載的優(yōu)先級(jí),對(duì)于保障應(yīng)用的安全性、可維護(hù)性以及降低部署復(fù)雜度至關(guān)重要。特別是在大規(guī)模微服務(wù)架構(gòu)中,合理的配置管理和遷移對(duì)于整體系統(tǒng)的穩(wěn)定性有著不可忽視的作用。通過(guò)對(duì)配置優(yōu)先級(jí)的深入掌控,開(kāi)發(fā)者和運(yùn)維人員能夠輕松應(yīng)對(duì)復(fù)雜環(huán)境下的配置管理挑戰(zhàn),使得Spring Boot應(yīng)用具備良好的擴(kuò)展性和適應(yīng)性。
本文已收錄于我的個(gè)人博客: 碼農(nóng)Academy的博客,專注分享Java技術(shù)干貨,包括Java基礎(chǔ)、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中間件、架構(gòu)設(shè)計(jì)、面試題、程序員攻略等
如何使用 Pytorch 中的 DataSet 和 DataLoader
閱讀golang slice相關(guān)常見(jiàn)的性能優(yōu)化手段
閱讀連接Elasticsearch服務(wù)器的Python代碼示例
閱讀國(guó)產(chǎn)操作系統(tǒng)上實(shí)現(xiàn)RTMP推流攝像頭視頻和麥克風(fēng)聲音到流媒體服務(wù)器
閱讀使用Python讀取和導(dǎo)出NetCDF格式的多時(shí)相柵格文件
閱讀多租戶系統(tǒng)數(shù)據(jù)權(quán)限設(shè)計(jì)與RuoYi系統(tǒng)的借鑒
閱讀count(*)、count(1)哪個(gè)更快?面試必問(wèn):通宵整理的十道經(jīng)典MySQL必問(wèn)面試題
閱讀從需求分析、產(chǎn)品設(shè)計(jì)到部署交付各階段說(shuō)明
閱讀如何利用七牛云進(jìn)行數(shù)據(jù)備份和刪除
閱讀強(qiáng)化學(xué)習(xí)筆記之【ACE:Off-PolicyActor-CriticwithCausality-AwareEntropyRegularization】
閱讀使用MailKit在.NET Core中收發(fā)郵件的完整示例
閱讀本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請(qǐng)發(fā)郵件[email protected]
湘ICP備2022002427號(hào)-10 湘公網(wǎng)安備:43070202000427號(hào)© 2013~2024 haote.com 好特網(wǎng)