自動(dòng)配置的使用
配置是Spring Framework的核心元素失球,必須要有東西告訴Spring如何應(yīng)用程序精堕。當(dāng)你引入Spring Boot時(shí)悍引,有個(gè)名為spring-boot-autoconfigure
的JAR文件凰慈,其中包含了很多配置類(lèi)官紫。每個(gè)配置類(lèi)都在應(yīng)用程序的Classpath里引瀑,當(dāng)條件適當(dāng)時(shí)就會(huì)啟用這些配置類(lèi)狂芋。
那么什么時(shí)候算是條件適當(dāng)呢?
下面這張表格就是自動(dòng)配置中使用的條件化注解憨栽,上面限定了一些配置生效條件帜矾。這是Spring 4.0提供的條件化配置,可以判斷這個(gè)配置是該被應(yīng)用還是被忽略.
舉個(gè)例子
這是Spring Boot自動(dòng)配置庫(kù)中的一個(gè)數(shù)據(jù)源配置類(lèi)。
這里添加了@ConditionOnClass({DataSource.class, EmbeddedDatabaseType.class})
注解,要求Classpath里必須有DataSource
和EmbeddedDatabaseType
.如果它們不存在,條件就不成立,DataSourceAutoConfiguration
提供的配置都會(huì)被忽略掉徒像。
當(dāng)你想要覆蓋Spring Boot的自動(dòng)配置,只需要寫(xiě)一個(gè)顯示的配置類(lèi),添加@Configuration
注解,或是在xml文檔中進(jìn)行配置,Spring Boot會(huì)發(fā)現(xiàn)你的配置,使自動(dòng)配置類(lèi)不生效,以你的配置為準(zhǔn).
上表中的ConditionOnMissingBean
注解是覆蓋自動(dòng)配置的關(guān)鍵.舉個(gè)覆蓋自動(dòng)配置的例子黍特。
這是DataSourceAutoConfiguration
類(lèi)中的一個(gè)方法,ConditionOnMissingBean({DataSource.class,XADataSource.class})
,要求當(dāng)前不存在DataSource.class
、XADataSource.class
才生效.如果當(dāng)前已經(jīng)有了這兩個(gè)Bean,條件既不滿足,不會(huì)執(zhí)行PooledDataSourceConfiguration
方法锯蛀。
如果上面表格的條件化注解不適用時(shí)灭衷,可以實(shí)現(xiàn)Condition
接口的match()
方法,然后結(jié)合Conditional
注解自定義配置生效條件旁涤。
自動(dòng)配置的源碼分析
從上圖可以看出SpringBoot的啟動(dòng)類(lèi)上的注解SpringBootApplecation
都包含有EnableAutoConfiguration
注解,意味著啟用自動(dòng)配置翔曲。
跟進(jìn)EnableAutoConfiguration
類(lèi)中發(fā)現(xiàn)含有@Import({AutoConfigurationImportSelector.class})
注解,@Import
注解也是將類(lèi)加載進(jìn)Spring容器中,這里導(dǎo)入了類(lèi)AutoConfigurationImportSelector
字面意思上看是一個(gè)自動(dòng)配置導(dǎo)入的選擇器類(lèi)迫像。
上圖可以看出,自動(dòng)配置大致可以分為三步瞳遍。
- 檢查注解是否開(kāi)啟
- 讀取自動(dòng)配置元數(shù)據(jù)闻妓,其實(shí)就是自動(dòng)配置類(lèi)的注解屬性
- 獲取符合條件的自動(dòng)配置類(lèi)
第一步,注解是否開(kāi)啟
? 這步其實(shí)就是獲取環(huán)境變量掠械,將注解類(lèi)的值進(jìn)行比較由缆。
第二步,讀取自動(dòng)配置元數(shù)據(jù)
? 跟進(jìn)方法
META-INF/spring-autoconfigure-metadata.properties里頭放了定義了很多默認(rèn)自動(dòng)配置類(lèi)的關(guān)聯(lián)配置類(lèi)以及生效條件的指定類(lèi).
這有一個(gè)selectImports
方法,通過(guò)loadMetadata()
方法加載META-INF/spring-autoconfigure-metadata.properties猾蒂,存放到內(nèi)部靜態(tài)類(lèi)AutoConfigurationEntry
中,這個(gè)類(lèi)存放了配置類(lèi)的類(lèi)名以及需要排除的類(lèi)名.
第三步均唉,執(zhí)行getAutoConfigurationEntry()
方法,根據(jù)第二步讀取的自動(dòng)配置類(lèi)的注解屬性,開(kāi)始獲取需要生效的配置類(lèi)列表肚菠。
這一步其實(shí)就是根據(jù)自帶的兩個(gè)配置文件spring-autoconfigure-metadata.properties
舔箭、spring.factories
加載自動(dòng)配置類(lèi)、及自動(dòng)配置類(lèi)生效的條件蚊逢,根據(jù)這些內(nèi)容去過(guò)濾一些不符合條件层扶、重復(fù)的自動(dòng)配置類(lèi),最后返回一個(gè)需要生效的自動(dòng)配置類(lèi)列表烙荷。
什么時(shí)候執(zhí)行selectImports()
?
Spring boot應(yīng)用啟動(dòng)過(guò)程中使用ConfigurationClassParser
分析配置類(lèi) (比如使用了@Configuration
的注解類(lèi))時(shí)镜会,如果發(fā)現(xiàn)注解中存在@Import(AutoConfigurationImportSelector.class)
的情況,就會(huì)創(chuàng)建一個(gè)相應(yīng)的AutoConfigurationImportSelector
對(duì)象奢讨, 并調(diào)用其selectImports(AnnotationMetadata annotationMetadata
對(duì)象方法public String[] selectImports(AnnotationMetadata annotationMetadata)
稚叹。
這里 @EnableAutoConfiguration
的導(dǎo)入@Import(EnableAutoConfigurationImportSelector.class)
就屬于這種情況【發(fā)現(xiàn)有@import注解,那么就對(duì)該導(dǎo)入類(lèi)進(jìn)行一個(gè)事例化】,所以ConfigurationClassParser會(huì)實(shí)例化一個(gè) EnableAutoConfigurationImportSelector 并調(diào)用它的 selectImports() 方法拿诸。
Spring的工具類(lèi)ConfigurationClassParser用于分析@Configuration注解的配置類(lèi)扒袖,產(chǎn)生一組ConfigurationClass對(duì)象。它的分析過(guò)程會(huì)接受一組種子配置類(lèi)(調(diào)用者已知的配置類(lèi)亩码,通常很可能只有一個(gè))季率,從這些種子配置類(lèi)開(kāi)始分析所有關(guān)聯(lián)的配置類(lèi),分析過(guò)程主要是遞歸分析配置類(lèi)的注解@Import描沟,配置類(lèi)內(nèi)部嵌套類(lèi)飒泻,找出其中所有的配置類(lèi),然后返回這組配置類(lèi)吏廉。
該工具主要由ConfigurationClassPostProcessor使用泞遗,而ConfigurationClassPostProcessor是一個(gè)BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor,它會(huì)在容器啟動(dòng)過(guò)程中,應(yīng)用上下文上執(zhí)行各個(gè)BeanFactoryPostProcessor時(shí)被執(zhí)行席覆。