SpringBoot外部化配置示例解析
SpringBoot外部化配置(基于2.4.0以后)
Spring Boot可以讓你將配置外部化,這樣你就可以在不同的環(huán)境中使用相同的應用程序代碼。 你可以使用各種外部配置源,包括Java properties 文件、YAML文件、環(huán)境變量和命令行參數(shù)。
屬性值可以通過使用 @Value 注解直接注入你的Bean,也可以通過Spring 的 Environment 訪問,或者通過 @ConfigurationProperties 綁定到對象。同時 Spring Boot 也提供了一種非常特殊的 PropertyOrder,來允許用戶可以在適當?shù)膱鼍跋赂采w某些屬性值,該順序旨在允許合理地覆蓋值。
按以下順序優(yōu)先級從低到高, 后者的屬性值覆蓋前者 ,所有的配置會形成互補配置:
默認屬性(使用 SpringApplication.setDefaultProperties 指定)
@Configuration
類上的@PropertySource
注解引入的配置屬性
請注意,這樣的屬性源直到ApplicationContext
被刷新時才會被添加到環(huán)境中。這對于配置某些屬性來說已經(jīng)太晚了,比如logging.*
和spring.main.*
,它們在刷新開始前就已經(jīng)被讀取了。
配置數(shù)據(jù)(例如application.properties文件)
對于random.*
形式的屬性,優(yōu)先從RandomValuePropertySource
獲?。ㄖ竷?yōu)先于后者)
OS environment variables((操作系統(tǒng)環(huán)境變量)
Java System properties(Java 系統(tǒng)屬性System.getProperties()
)
JNDI 屬性
ServletContext 的 初始化參數(shù)
ServletConfig 的 初始化參數(shù)
SPRING_APPLICATION_JSON 屬性
命令行參數(shù)
test 模塊下的 properties 屬性
test 模塊下 @TestPropertySource 注解引入的配置文件
啟用 devtools 時 $HOME/.config/spring-boot 路徑下的配置
配置數(shù)據(jù)文件按以下加載順序考慮:
- 打包在 jar 中的應用程序屬性(application.properties 和 YAML)
- 打包在 jar 中的特定配置文件的應用程序屬性(application-{profile}.properties 和 YAML)
- 打包 jar 之外的應用程序屬性(application.properties 和 YAML)
- 打包 jar 之外的特定配置文件的應用程序屬性(application-{profile}.properties 和 YAML)
SpringBoot配置文件
Spring中常見的配置文件類型
- XML資源
- Properties資源
- YAML資源
Profile概述
Profile 本質(zhì)上代表一種用于組織配置信息的維度,在不同場景下可以代表不同的含義。例如,如果 Profile 代表的是一種狀態(tài),我們可以使用 open、halfopen、close 等值來分別代表全開、半開和關閉等。再比如系統(tǒng)需要設置一系列的模板,每個模板中保存著一系列配置項。
配置命名規(guī)則:
/{application}.yml /{application}-{profile}.yml /{label}/{application}-{profile}.yml /{application}-{profile}.properties /{label}/{application}-{profile}.properties
配置文件加載順序
Spring Boot 啟動時,會自動加載 JAR 包內(nèi)部及 JAR 包所在目錄指定位置的配置文件(Properties 文件、YAML 文件)。列表按優(yōu)先級排序(較低項目的值覆蓋較早項目的值)
classpath( –classpath )
classpath 根路徑
classpath 下的 /config 包
當前目錄( –file )
當前目錄下
當前目錄下的 config/ 子目錄
當前目錄下的 config/ 子目錄的直接子目錄
. project-sample ├── config │ ├── application.yml (4) │ └── src/main/resources | │ ├── application.yml (1) | │ └── config | | │ ├── application.yml (2) ├── application.yml (3)
啟動時加載配置文件順序:1 > 2 > 3 > 4
Profile 配置覆蓋變更(2.4.0以后)
2.4.0
以前版本,默認情況的加載順序如下:
- 打包在 jar 中的應用程序屬性(application.properties 和 YAML)。
- 打包 jar 之外的應用程序屬性(application.properties 和 YAML)
- 打包在 jar 中的特定于配置文件的應用程序屬性(application-{profile}.properties 和 YAML)
- 打包 jar 之外的特定于配置文件的應用程序屬性(application-{profile}.properties 和 YAML)
注意:在之前的版本中,JAR 包外部的application.properties
配置文件不會覆蓋 JAR 包里面的基于 "profile" 的application-{profile}.properties
配置文件。
2.4.0
以后版本,默認情況的搜索順序如下:保證了 JAR 包外部的應用程序參數(shù)應優(yōu)先于 JAR 包內(nèi)部的特定激活的配置參數(shù)
- 打包在 jar 中的應用程序屬性(application.properties 和 YAML)。
- 打包在 jar 中的特定于配置文件的應用程序屬性(application-{profile}.properties 和 YAML)
- 打包 jar 之外的應用程序屬性(application.properties 和 YAML)
- 打包 jar 之外的特定于配置文件的應用程序屬性(application-{profile}.properties 和 YAML)
注意:同一位置下,Properties 文件優(yōu)先級高于 YAML 文件 , 如果Spring Boot在優(yōu)先級更高的位置找到了配置,那么它就會無視優(yōu)先級低的配置。
文檔排序(2.4.0以后)
從 Spring Boot 2.4 開始,加載 Properties 和 YAML 文件時候會遵循, 在文檔中聲明排序靠前的屬性將被靠后的屬性覆蓋 。
激活指定配置文件
命令行激活: --spring.profiles.active=prod
spring: profiles: active: dev #激活開發(fā)環(huán)境配置
配置文件激活如上,只需要在application.yml或者properties文件中配置即可
注意:在application.yml或者properties文件存在的情況下,不管激活的是prod還是dev,還是會讀取默認的配置文件,只不過指定的配置文件會覆蓋默認配置文件中的屬性
導入額外的配置文件(2.4.0以后)
可以使用spring.config.import
屬性從其他地方導入更多的配置數(shù)據(jù),比如spring.config.import=my.yaml
。它會將 my.yaml 文件作為臨時文件放在當前配置文件之后處理,因此其屬性具有更高的優(yōu)先級
激活外部配置文件
在運行Jar
包的命令中加入這個參數(shù)就可以指定Jar
包以外的配置文件的位置了,也可以在application的配置文件中配置該屬性
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
這個參數(shù)就是指定外部application.yml
配置文件位置的參數(shù),它支持classpath
和file
路徑
java -jar myproject.jar --spring.config.name=myproject
如果您不喜歡application.properties
作為配置文件名,您可以通過指定spring.config.name
環(huán)境屬性來切換到另一個文件名
optional可選的配置文件
對于spring.config.location
、spring.config.additional-location
和spring.config.import
等屬性的路徑,添加optional:
前綴,則當對應文件不存在時應用仍可以正常啟動
比如spring.config.location=optional:file:/my.yaml
,當應用啟動加載文件 my.yaml 不存在時,不會拋出異常
嵌入系統(tǒng)配置信息
例如,如果想要獲取當前應用程序的名稱并作為一個配置項進行管理,那么很簡單,我們直接通過 ${spring.application.name} 占位符:
myapplication.name : ${spring.application.name}
假設我們使用 Maven 來構建應用程序,那么可以按如下所示的配置項來動態(tài)獲取與系統(tǒng)構建過程相關的信息:
info: app: encoding: @project.build.sourceEncoding@ java: source: @java.version@ target: @java.version@ # 等同于下述效果 info: app: encoding: UTF-8 java: source: 1.8.0_31 target: 1.8.0_31
配置參數(shù)提示
additional-spring-configuration-metadata.json
、spring-configuration-metadata.json
在springboot-starter官方項目或第三方starter項目中隨處可見,那它起的作用是什么?
- 配置
additional-spring-configuration-metadata.json
文件后,在開發(fā)人員的IDE工具使用個人編寫的配置讀取很有效的在application.properties
或application.yml
文件下完成提示
配置處理器
在Maven中,該依賴關系應被聲明為可選的,如以下例子所示。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
創(chuàng)建additional-spring-configuration-metadata.json
在resources/META-INF
目錄下創(chuàng)建additional-spring-configuration-metadata.json
,分類為 “groups” 或 “properties”,附加值提示分類為 "hints",如以下例子所示:
{ "groups": [ { "name": "server", "type": "org.springframework.boot.autoconfigure.web.ServerProperties", "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties" }, { "name": "spring.jpa.hibernate", "type": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties$Hibernate", "sourceType": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties", "sourceMethod": "getHibernate()" } ... ], "properties": [ { "name": "server.port", "type": "java.lang.Integer", "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties" }, { "name": "server.address", "type": "java.net.InetAddress", "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties" }, { "name": "spring.jpa.hibernate.ddl-auto", "type": "java.lang.String", "description": "DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" property.", "sourceType": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties$Hibernate" } ... ], "hints": [ { "name": "spring.jpa.hibernate.ddl-auto", "values": [ { "value": "none", "description": "Disable DDL handling." }, { "value": "validate", "description": "Validate the schema, make no changes to the database." }, { "value": "update", "description": "Update the schema if necessary." }, { "value": "create", "description": "Create the schema and destroy previous data." }, { "value": "create-drop", "description": "Create and then destroy the schema at the end of the session." } ] } ] }
Property 屬性
properties 數(shù)組中包含的JSON對象可以包含下表中描述的屬性。
Name | 類型 | 目的 |
---|---|---|
name | String | 屬性的全名。 名稱采用小寫的句號分隔形式(例如,server.address)。 這個屬性是強制性的。 |
type | String | 該屬性的數(shù)據(jù)類型的完整簽名(例如,java.lang.String),但也有完整的通用類型(例如 java.util.Map<java.lang.String,com.example.MyEnum>)。 您可以使用此屬性來指導用戶可以輸入的值的類型。 為了保持一致性,基元的類型是通過使用其包裝類型來指定的(例如,boolean 變成 java.lang.Boolean)。 如果該類型不知道,可以省略。 |
description | String | 可以顯示給用戶的該property的簡短描述。 如果沒有描述,可以省略。 描述中的最后一行應以句號(.)結束。 |
sourceType | String | 貢獻此屬性的來源的類名。 例如,如果該屬性來自于一個用 @ConfigurationProperties 注解的類,該屬性將包含該類的完全限定名稱。 如果源類型未知,可以省略。 |
defaultValue | Object | 默認值,如果沒有指定該屬性,則使用該值。 如果該屬性的類型是一個數(shù)組,它可以是一個數(shù)組的值。 如果默認值是未知的,它可以被省略。 |
deprecation | Deprecation | 指定該屬性是否被廢棄。 如果該字段沒有被廢棄,或者不知道該信息,可以省略。 下表提供了關于 deprecation 屬性的更多細節(jié)。 |
Hint 屬性
包含在 hints 數(shù)組中的JSON對象可以包含下表中的屬性。
Name | 類型 | 目的 |
---|---|---|
name | String | 此提示所指向的屬性的全名。 名稱采用小寫的句號分隔形式(如 spring.mvc.servlet.path)。 這個屬性是強制性的。 |
values | ValueHint[] | 由 ValueHint 對象定義的有效值的列表(在下表中描述)。 每個條目都定義了值,并且可以有一個description。 |
每個 hint 元素的 values 屬性中包含的JSON對象可以包含下表中描述的屬性。
Name | 類型 | 目的 |
---|---|---|
value | Object | 提示所指的元素的一個有效值。 如果該屬性的類型是一個數(shù)組,它也可以是一個數(shù)組的值。 這個屬性是強制性的。 |
description | String | 可以顯示給用戶的價值的簡短描述。 如果沒有描述,可以省略。 描述中的最后一行應以句號(.)結束。 |
SpringBoot命令行參數(shù)
參考:http://www.dbjr.com.cn/article/191629.htm
啟動Spring Boot項目時傳遞參數(shù),有三種參數(shù)形式:
- 選項參數(shù),基本格式為
--optName[=optValue]
(--
為連續(xù)兩個減號)
--foo --foo=bar --foo="bar then baz" --foo=bar,baz,biz
- 非選項參數(shù)
java -jar xxx.jar abc def
- 系統(tǒng)參數(shù)
java -jar -Dserver.port=8081 xxx.jar
相當于 SpringBoot 基于 Java 命令行參數(shù)中的非選項參數(shù)自定義了選項參數(shù)的規(guī)則,具體可以看解析器SimpleCommandLineArgsParser
,它里面調(diào)用其parse
方法對參數(shù)進行解析
class SimpleCommandLineArgsParser { public CommandLineArgs parse(String... args) { CommandLineArgs commandLineArgs = new CommandLineArgs(); for (String arg : args) { // --開頭的選參數(shù)解析 if (arg.startsWith("--")) { // 獲得key=value或key值 String optionText = arg.substring(2, arg.length()); String optionName; String optionValue = null; // 如果是key=value格式則進行解析 if (optionText.contains("=")) { optionName = optionText.substring(0, optionText.indexOf('=')); optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length()); } else { // 如果是僅有key(--foo)則獲取其值 optionName = optionText; } // 如果optionName為空或者optionValue不為空但optionName為空則拋出異常 if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) { throw new IllegalArgumentException("Invalid argument syntax: " + arg); } // 封裝入CommandLineArgs commandLineArgs.addOptionArg(optionName, optionValue); } else { commandLineArgs.addNonOptionArg(arg); } } return commandLineArgs; } }
參數(shù)值的獲取
如果您需要訪問傳遞給應用程序的參數(shù)SpringApplication.run(…)
,您可以注入一個ApplicationArguments
。該ApplicationArguments
接口提供對原始String[]
參數(shù)以及選項參數(shù)和非選項參數(shù)的訪問,如以下示例所示:
@Component public class MyBean { @Autowired public MyBean(ApplicationArguments args) { boolean debug = args.containsOption("debug"); List<String> files = args.getNonOptionArgs(); // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"] } }
- 另外,選項參數(shù),也可以直接通過
@Value
在類中獲取 - 系統(tǒng)參數(shù)可以通過java.lang.System提供的方法獲取
參數(shù)值的區(qū)別
關于參數(shù)值區(qū)別,重點看選項參數(shù)和系統(tǒng)參數(shù)。通過上面的示例我們已經(jīng)發(fā)現(xiàn)使用選項參數(shù)時,參數(shù)在命令中是位于xxx.jar
之后傳遞的,而系統(tǒng)參數(shù)是緊隨java -jar
之后。
如果不按照該順序進行執(zhí)行,比如使用如下方式使用選項參數(shù):
java -jar --server.port=8081 xxx.jar
則會拋出如下異常:
Unrecognized option: --server.port=8081 Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.
如果將系統(tǒng)參數(shù)放在jar包后面,問題會更嚴重,會出現(xiàn)可以正常啟動,但參數(shù)無法生效。這個錯誤是最坑的,所以一定謹記:通過-D傳遞系統(tǒng)參數(shù)時,務必放置在待執(zhí)行的jar包之前。
擴展“外部化配置”屬性源
SpingBoot怎么支持YAML配置文件解析?
處理@PropertySource注解從ConfigurationClassParser#processPropertySource方法進
Spring中@PropertySource默認不支持YAML格式的解析,但是SpringBoot的配置文件卻可以解析YAML,這說明SpringBoot中已經(jīng)實現(xiàn)了YAML文件的解析,我們只需要復用即可,我們可以看該注解源碼
/** * Specify a custom {@link PropertySourceFactory}, if any. * <p>By default, a default factory for standard resource files will be used. * @since 4.3 * @see org.springframework.core.io.support.DefaultPropertySourceFactory * @see org.springframework.core.io.support.ResourcePropertySource */ Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
PropertySourceFactory的默認實現(xiàn)是DefaultPropertySourceFactory
public class DefaultPropertySourceFactory implements PropertySourceFactory { @Override public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException { return (name != null ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource)); } }
ResourcePropertySource默認不支持YAML,所以我們可以通過實現(xiàn)PropertySourceFactory接口,然后用@PropertySource的factory屬性來實現(xiàn)YAML的解析
public class YamlPropertySourceFactory implements PropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean(); yamlPropertiesFactoryBean.setResources(resource.getResource()); Properties yamlProperties = yamlPropertiesFactoryBean.getObject(); return new PropertiesPropertySource(name, yamlProperties); } }
關于ApplicationEnvironmentPreparedEvent沒有被執(zhí)行的原因
官方文檔中有說到:有些事件實際上是在ApplicationContext被創(chuàng)建之前觸發(fā)的,所以我們不能將這些事件的監(jiān)聽器注冊為@Bean。
因為這個時候應用上下文還沒有被創(chuàng)建,也就是說監(jiān)聽器也還沒有被初始化,這個先后順序不對,會導致這些事件的監(jiān)聽器不會被觸發(fā)
但可以使用SpringApplication.addListeners(...)
方法或SpringApplicationBuilder.listeners(...)
方法注冊它們。
如果您希望這些偵聽器自動注冊的話,可以通過新建一個META-INF/spring.factories
文件,添加類似以下內(nèi)容,SpringBoot會自動幫你注冊。
org.springframework.context.ApplicationListener=com.example.project.MyListener
應用程序事件
應用程序運行時,應用程序事件按以下順序發(fā)送:官方鏈接
- An ApplicationStartingEvent is sent at the start of a run but before any processing, except for the registration of listeners and initializers.
- An ApplicationEnvironmentPreparedEvent is sent when the Environment to be used in the context is known but before the context is created.
- An ApplicationContextInitializedEvent is sent when the ApplicationContext is prepared and ApplicationContextInitializers have been called but before any bean definitions are loaded.
- An ApplicationPreparedEvent is sent just before the refresh is started but after bean definitions have been loaded.
- An ApplicationStartedEvent is sent after the context has been refreshed but before any application and command-line runners have been called.
- An AvailabilityChangeEvent is sent right after with LivenessState.CORRECT to indicate that the application is considered as live.
- An ApplicationReadyEvent is sent after any application and command-line runners have been called.
- An AvailabilityChangeEvent is sent right after with ReadinessState.ACCEPTING_TRAFFIC to indicate that the application is ready to service requests.
- An ApplicationFailedEvent is sent if there is an exception on startup.
The above list only includes SpringApplicationEvents that are tied to a SpringApplication. In addition to these, the following events are also published after ApplicationPreparedEvent and before ApplicationStartedEvent:
- A WebServerInitializedEvent is sent after the WebServer is ready. ServletWebServerInitializedEvent and ReactiveWebServerInitializedEvent are the servlet and reactive variants respectively.
- A ContextRefreshedEvent is sent when an ApplicationContext is refreshed.
以上就是SpringBoot外部化配置示例解析的詳細內(nèi)容,更多關于SpringBoot外部化配置的資料請關注腳本之家其它相關文章!
相關文章
SpringBoot Application的exclude不生效問題及排查
這篇文章主要介紹了SpringBoot Application的exclude不生效問題及排查,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11SpringBoot項目application.yml文件數(shù)據(jù)庫配置密碼加密的方法
這篇文章主要介紹了SpringBoot項目application.yml文件數(shù)據(jù)庫配置密碼加密的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-03-03使用Spring AOP監(jiān)控指定方法執(zhí)行時間的代碼詳解
這篇文章主要介紹了使用Spring AOP監(jiān)控指定方法執(zhí)行時間,文中通過代碼示例給大家介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2024-08-08java.math.BigDecimal的用法及加減乘除計算
這篇文章主要介紹了java.math.BigDecimal的用法及加減乘除計算,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05Springboot+Flowable?快速實現(xiàn)工作流的開發(fā)流程
這篇文章主要介紹了Springboot+Flowable?快速實現(xiàn)工作流的開發(fā)流程,本文通過實例代碼圖文相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02