配置形式
spring-boot的配置包括:
自動配置
外化配置
外化配置通過將可變量分離出來,使得我們可以在不同的環境中使用同一份代碼。
外化配置表現形式不單單是 .properties 和 .yml 屬性文件,還可以使用環境變量和命令行參數等來實現。
由於有好多外部配置來源,所以需要解決配置衝突問題,解決方案是通過優先級,下面是屬性讀取順序:
本地 Devtools 全局配置
測試時 @TestPropertySource 註解配置
測試時 @SpringBootTest 註解的 properties 配置
命令行配置
SPRINGAPPLICATIONJSON 配置
ServletConfig 初始化參數配置
ServletContext 初始化參數配置
Java 環境的 JNDI 參數配置
Java 系統的屬性配置
OS 環境變量配置
只能隨機屬性的 RandomValuePropertySource 配置
工程 jar 之外的多環境配置文件(application- {profile}.properties 或 YAML)
工程 jar 之內的多環境配置文件(application- {profile}.properties 或 YAML)
工程 jar 之外的應用配置文件(application.properties 或 YAML)
工程 jar 之內的應用配置文件(application.properties 或 YAML)
@Configuration 類中的 @PropertySource 註解配置
默認屬性配置(SpringApplication.setDefaultProperties 指定)
配置使用方法
講了配置後,下一步就是介紹使用方法了:
通過@Value註解
通過@ConfigurationProperties綁定到配置類上
通過Environment獲取
先看第一個@Value註解
第二個@ConfigurationProperties註解
這個東西是個啥呢?看代碼:
順著代碼註釋我們去看ConfigurationPropertiesBindingPostProcessor和EnableConfigurationProperties。
ConfigurationPropertiesBindingPostProcessor
我們先來看ConfigurationPropertiesBindingPostProcessor:
上面繼承圖中 ApplicationContextAware 是 Spring 提供的獲取 Spring 上下文中指定對象的方法,會在 BeanPostProcessor 之前調用,我們先來看 BeanPostProcessor。
BeanPostProcessor
BeanPostProcessor 接口定義了兩個方法:
postProcessBeforeInitialization:在 Bean 初始化回調前調用
postProcessAfterInitialization:在 Bean 初始化回調完成後進行調用,而且會在 afterPropertiesSet 方法回調之後。
所以我們只需要實現BeanPostProcessor接口,就能夠控制Bean初始化前後的操作。
下面我們來探究下到底是怎麼實現的,查看實現的原理的萬能方式是打斷點調試,來看下我們調用棧:
我們先來看第一個方法:AbstractAutowireCapableBeanFactory.initializeBean,
上面我們列舉出了主要的方法,看名字大概就能知道功能,來看applyBeanPostProcessorsAfterInitialization。
看裡面的重點函數getBeanPostProcessors。
InitializingBean 中 afterPropertiesSet 方法處打斷點。
可以說是看到了老朋友,也是AbstractAutowireCapableBeanFactory.initializeBean方法,裡面的initializeBean方法如下:
EnableConfigurationProperties
還記得之前的圖:
介紹完 ConfigurationPropertiesBindingPostProcessor 後,我們介紹 EnableConfigurationProperties。
@Import 可以將對應的 Bean 導入到 Spring 上下文中。如果類在工程中的話那麼直接使用 @Configuration 註解即可,Spring 會自動識別的。但是如果在其他 jar 包或框架上,沒有配置到自動掃描的目錄中或者是沒有添加 @Configuration 註解,那麼就需要使用 @Import 將其導入到項目中來。
到這裡我們來捋下整個思路:
我們的出發點是想看 為何加個註解 ConfigurationProperties 到類上,就能實現自動屬性注入了
我們去看了註解 ConfigurationProperties 的定義,註釋中讓我們去看 ConfigurationPropertiesBindingPostProcessor 和 EnableConfigurationProperties
我們先去看了 ConfigurationPropertiesBindingPostProcessor ,給出了類的繼承圖,上面需要關注的是 BeanPostProcessor 和 InitializingBean
BeanPostProcessor 和 InitializingBean 一起給加載 Bean 的過程中流出了3個擴展點,調用的順序是:postProcessBeforeInitialization -> afterPropertiesSet -> postProcessAfterInitialization
在 postProcessBeforeInitialization 中完成了屬性的綁定
接著我們要去看 EnableConfigurationProperties 註解,發現裡面的@Import是加載需要的Bean進來
以上就是我們目前的一個解決問題的思路,下面我們來看 EnableConfigurationProperties 這個Enable**是在哪個地方引入到SpringBoot中的呢?
我們會發現在包org.springframework.boot.autoconfigure下的context.ConfigurationPropertiesAutoConfiguration:
至於 ConfigurationPropertiesAutoConfiguration 這個加載進來呢?
這就到了 Spring-boot的精髓 EnableAutoConfiguration 。
EnableAutoConfiguration
我們可以在包org.springframework.boot.autoconfigure中的spring.factories中定義了好多自動配置的類:
所以我們就到了EnableAutoConfiguration:
接著我們就會到了@SpringBootApplication,裡面有註解 EnableAutoConfiguration
我們下一步自然就進入@Import(AutoConfigurationImportSelector.class),裡面的 selectImports 將 Bean 加載進來:
其中 DeferredImportSelector 的作用是在所有Bean處理完後最後再處理,特別適合Bean是根據條件Import進來的。
挨行來看代碼,
讀取了 META-INF/spring-autoconfigure-metadata.properties 配置文件,改配置文件中的內容如下:
配置文件中配置了 SpringBoot 自動集成的各種 Enable 框架的執行條件,比如定義與其他 AutoConfiguration 框架的執行順序,需要哪些 Bean 在的時候才可以執行等。
整個流程如下:
圖片來自 第05課:@EnableAutoConfiguration 原理與實戰
EnableConfigurationPropertiesImportSelector
到這我們將介紹我們最後一部分,我們瞭解了 EnableConfigurationProperties 是如何開啟的了,下面就看其加載進入了哪些Bean進來。
我們先不看代碼,先講下這個邏輯,我們有@SpringBootApplication,其開啟了@EnableAutoConfiguration,而 @EnableAutoConfiguration 會通過@Import去加載進 META-INF/spring-autoconfigure-metadata.properties 中定義的 autoconfigure 類來, 而其中就包含了 EnableConfigurationProperties,下面我們就看看 EnableConfigurationProperties 的 @Import 去將有相關 的Bean加載進來了,整個邏輯清晰後,我們就能來看 EnableConfigurationPropertiesImportSelector 了,具體方法還是打斷點,裡面會有兩個方法來註冊Bean。
會將 EnableConfigurationProperties 中寫的Bean註冊進來,一個例子就是:
上面會將JacksonProperties加載進來。
這裡就將我們之前介紹的ConfigurationPropertiesBindingPostProcessor加載了進來。
總結
以上就是我們的整個spring-boot的配置原理解析,總結下整個思路:
我們的出發點是想看 為何加個註解 ConfigurationProperties 到類上,就能實現自動屬性注入了
我們去看了註解 ConfigurationProperties 的定義,註釋中讓我們去看 ConfigurationPropertiesBindingPostProcessor 和 EnableConfigurationProperties
我們先去看了 ConfigurationPropertiesBindingPostProcessor ,給出了類的繼承圖,上面需要關注的是 BeanPostProcessor 和 InitializingBean
BeanPostProcessor 和 InitializingBean 一起給加載 Bean 的過程中流出了3個擴展點,調用的順序是:postProcessBeforeInitialization -> afterPropertiesSet -> postProcessAfterInitialization
在 postProcessBeforeInitialization 中完成了屬性的綁定
接著我們要去看 EnableConfigurationProperties 註解,發現裡面的@Import是加載需要的Bean進來
EnableConfigurationProperties @Import 進來的Bean就包含了之前的 ConfigurationPropertiesBindingPostProcessor
閱讀更多 程序猿的進擊之路 的文章