Spring Boot支持的配置方式有哪些(深度解析)

Spring Boot支持的配置方式有哪些(深度解析)

有本書上總結了一下,大概有9種配置方式,當然還有其他方式,這裏不再列舉。並且這些配置方式是有優先級的,如果不同的配置方式都配置了同一個配置項,那麼優先級高的勝出。下面我們來具體看。

 

 

一,Spring Boot支持的配置方式

 

 

 

Spring Boot配置的核心類是PropertySource<T>,這個類是抽象類,定義了獲取配置信息的基本操作。

下面我們結合源碼和測試驗證,來具體分析。

 

1,命令行參數。

什麼是命令行參數呢?就是我們啓動Spring Boot時,SpringApplication#run方法的入參中的第二個參數args。舉個例子:

SpringApplication.run(XxxApplication.class, "--spring.redis.timeout=60000");

這種方式就是命令行參數,但是我們一般不會這樣來配置,我們通常是這樣寫的:

SpringApplication.run(XxxApplication.class, args);

 

Spring Boot給我們提供了這種方式來配置,實際生產上我們不會使用,平時測試的時候可以使用,可以協助我們定位問題。

對應的解析類:CommandLinePropertySource<T>

 

2,通過System#getProperties方法獲取的java系統參數。

這部分系統參數,本質上是通過System#initProperties這個native方法來獲取的,這部分的優先級低於命令行參數配置方式。

舉個例子:假如我想覆蓋os.name這個配置項,那麼我可以使用命令行參數配置方式,如下:

SpringApplication.run(XxxApplication.class, "--os.name=IOS");

從這裏,我們也可以看出一個問題:命令行參數配置方式有很大的危險性,加入我通過命令行參數配置方式更改了系統參數,可能對系統來說,是災難性的。還好,Spring Boot給我們提供了禁用命令行參數配置的功能。

代碼如下:

// 創建springApplication實例

SpringApplication springApplication = new SpringApplication(XxxApplication.class);

// 禁用命令行參數

springApplication.setAddCommandLineProperties(false);
springApplication.run("--os.name=IOS");

 

 

3,操作系統環境變量。使用Docker啓動時,經常會設置系統變量。

 

這部分系統環境變量,我理解就是通過SyetemEnvironmentProropertySource導入的。正常情況下,也是通過native方法來獲取的,個人理解,只有通過命令行參數配置方式可以覆蓋,沒有其他修改入口。

 

4,從java:comp/env得到的JNDI屬性。

對應的解析類:JndiPropertySource

這種方式比較老了,本質上是通過FactoryBean的方式注入bean到IOC容器。

舉個例子:

Spring JNDI數據源配置信息:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">

<property name="jndiName">

<value>java:comp/env/jcptDataSourceJNDI</value>

</property>

</bean>

 

關於JNDI的配置(tomcat):

修改tomcat目錄conf/context.xml文件:

<Resource name="jcptDataSourceJNDI" auth="Container" type="javax.sql.DataSource"

maxActive="100" maxIdle="30" maxWait="10000" username="tysp"

password="12345678" driverClassName="oracle.jdbc.driver.OracleDriver"

url="jdbc:oracle:thin:@192.168.1.1:1521:OA"/>

 

通過JNDI獲取DataSource:

Context context = new InitialContext();
DataSource ds = (DataSource)context.lookup("java:comp/env/jcptDataSourceJNDI");

 

 

目前在Spring Boot中,這種方式很少使用了,我們一般是通過配置spring.datasource.*的方式來配置數據源,直接在properties文件或者yml文件中進行配置即可。

 

5,通過RandomValuePropertySource生成的random.*屬性。

對應的解析類:RandomValuePropertySource。

RandomValuePropertySource的使用也很少,Spring爲什麼要提供這個類呢?個人理解,是爲了在應用啓動階段,提供生產隨機數的功能,因爲有些場景可能會用到,比如每次啓動使用隨機的參數。一旦進入程序運行階段的話,我們就可以自己創建一個Random的實例了!

 

舉個例子:

xxx.uuid=${random.uuid}
xxx.intValue=${random.int}
redis.key.expireTime=${random.int[60000,120000]}

 

 

 

要注意,這個值會在項目啓動時生成並固定,每次重新啓動項目都會重新生成。

因爲RandomValuePropertySource的優先級高於我們的application.properties,所以我們可以在application.properties中使用random對象。

 

6,應用jar之外的屬性文件,如通過spring.config.location參數指定的屬性文件。

Spring boot 的Application.properties 配置文件可以是以下幾個地方:

classpath:/,classpath:/config/,file:./,file:./config/.

這4個路徑是默認的搜索路徑,我們還可以自定義配置文件存放路徑,就是通過spring.config.location來指定。

 

7,應用jar內部的屬性文件。

這一塊就是我們最熟悉的application.properties/application.yml配置文件了。具體的實現類是ConfigFileApplicationListener$ConfigurationProropertySource。

 

8,應用配置類(包含@Configuration註解的java類)中通過@PropertySource註解申明的屬性文件。

這種配置方式的優先級比較低,如果和我們系統默認的配置文件(application.properties)存在重複的配置項的話,將會被覆蓋。

 

9,通過SpringApplication#setDefaultProperties方法申明的默認屬性。

具體的實現類是MapProropertySource。

這部分配置最終會存放在Environment的defaultProperties這個屬性中。

 

 

 

二,Spring Boot配置優先級

 

 

接下來我們重點看看不同配置方式的優先級問題。

 

首先要搞清楚一個問題:如果一個配置項,比如:

spring.redis.timeout

我們既在bootstrap.properties中配置了,又在application.properties中配置了,那麼這2個配置項都會保存到我們的StandardServletEnvironment中。

bootstrap.properties中的配置被保存在了applicationConfig屬性中。

application.properties中的配置被保存在了applicationConfigurationProperties屬性中。

 

關於配置的優先級,我們這裏舉個例子,假如我們在application.properties配置了:

spring.redis.timeout=50000

然後我們在命令行也進行了如下配置:

SpringApplication.run(XxxApplication.class, "--spring.redis.timeout=60000");

因爲命令行參數的優先級高,我們在代碼中引用配置項spring.redis.timeout的話,取到的值是60000。

這就是Spring Boot各配置方式的優先級問題。

 

 

三,Spring Boot 項目中,環境Environment中包含的配置屬性

 

 

在Spring Boot中,Environment的具體實現是StandardServletEnvironment,StandardServletEnvironment中包含有一個ProropertySource(MutablePropertySource),這個屬性就是Spring Boot所有配置項的集合,裏面包含了所有的配置項。不管是通過哪種方式進行的配置,最終都會放到這個ProropertySource中。

 

源碼重點關注SpringApplication#prepareEnvironment方法,這個方法就是Spring Boot配置的核心處理方法。這裏有一部分的配置方式是通過監聽器來實現的,在Spring Boot啓動過程中,會觸發ApplicationEnvironmentPreparedEvent事件,然後通過多播器SimpleApplicationEventMulticaster通知監聽器,觸發監聽器的具體邏輯。

 

ProropertySource中包含以下屬性,這些屬性都是ProropertySource的具體實現。

 

bootstrapProperties:這個屬性包含了配置中心配置的某個微服務下的xxx_sale.properties配置文件中的所有配置項。

bootstrapProperties的具體實現是:CompositeProropertySource

 

servletConfigInitParams:具體實現是StubProropertySource。這個屬性加入到MutablePropertySource是在StandardServletEnvironment#customizePropertySources方法中。

 

servletContextInitParams:具體實現是StubProropertySource。這個屬性加入到MutablePropertySource是在StandardServletEnvironment#customizePropertySources方法中。

 

jndiProperties:這個屬性加入到MutablePropertySource是在StandardServletEnvironment#customizePropertySources方法中。

jndiProperties的數據結構是JndiPropertySource。

 

systemProperties:這個屬性包含了jvm的系統信息,比如操作系統相關信息,線程id等。這個屬性加入到MutablePropertySource是在StandardEnvironment#customizePropertySources方法中。感興趣的朋友可以看看源碼,最終是通過System#getProperties這個native方法獲取到系統參數的。systemProperties的數據結構是MapPropertySource。

 

systemEnvironment:這個屬性包含了jvm運行環境的信息,比如系統環境變量,ant路徑等。這個屬性加入到MutablePropertySource是在StandardEnvironment#customizePropertySources方法中。感興趣的朋友可以看看源碼,最終是通過System#getenv這個native方法獲取到系統參數的。

systemEnvironment的數據結構是SyetemEnvironmentProropertySource。

 

bootstrap:bootstrap是通過監聽器來實現的,在Spring Boot啓動過程中,會觸發ApplicationEnvironmentPreparedEvent事件,然後通過多播器SimpleApplicationEventMulticaster通知監聽器,觸發監聽器的具體邏輯。

bootstrap的監聽器實現是BootstrapApplicationListener#onApplicationEvent,實現邏輯還是挺複雜的,感興趣的朋友可以深入研究。

bootstrap的數據結構是MapProropertySource。

 

commandLineArgs:對應命令行參數配置方式,具體實現就在SpringApplication#run方法中,其中解析命令行參數配置的代碼是:

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

把commandLineArgs添加到MutablePropertySource的代碼是:

 

SpringApplication#configurePropertySources

commandLineArgs的數據結構是SimpleCommandLineProropertySource。

 

random:具體實現是RandomValueProropertySource。

 

applicationConfigurationProperties:這個屬性包含了application.properties配置文件中的所有配置項。

具體實現是ConfigFileApplicationListener$ConfigurationProropertySource。

 

applicationConfig:屬性包含了bootstrap.properties配置文件中的所有配置項。

具體實現是PropertiesProropertySource。

 

defaultProperties:這個屬性在SpringApplication#configurePropertySources方法中進行設置,最終是應用程序調用SpringApplication#setDefaultProperties進行設置的,優先級較低。defaultProperties的數據結構是MapProropertySource。

 

springCloudClientHostInfo:具體實現是MapProropertySource。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章