在SpringBoot中,不得不說的一個點就是自動裝配,它是starter的基礎,也是SpringBoot的核心,那麼什麼是自動裝配呢?showTime
自動裝配在SpringBoot中是通過@EnableAutoConfiguration的註解來實現的,而這個註解的聲明是在複合註解 @SpringBootApplication中
開始正餐之前先給大家說下其他註解
@SpringBootConfiguration 是一個聲明當前類是boot啓動類,是一個複合註解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
正餐開始 @EnableAutoConfiguration,跟蹤源碼點進去如下
當大家看到@AutoConfigurationPackage這個註解的時候是不是就豁然開朗,這就是爲什麼Spring掃描啓動類當前所在包及子包下的所有組件
大家如果經常閱讀源碼的話會看見@import和@Conditional這兩個註解,本節遇到了@import這個註解,我就先說明這個註解的作用:導入類。
@Import({AutoConfigurationImportSelector.class})
大家註解@import它導入的這個配置類是一個叫 AutoConfigurationImportSelector 這個一個配置類,當然就目前而言,不管這個類是做什麼的,大家一定得清楚就是它一定會實現配置類的導入,至於具體導入的方式和@Configuration有什麼區別,就是下面我要說明的
AutoConfigurationImportSelector這個類最終實現了ImportSelector,ImportSelector是一個接口,裏面有一個抽象方法,返回的是一個String數組,在這個數組中可以指定需要裝配到IOC容器的類,當在@Import中導入它的實現類侯,就會把該類中返回的Class名稱都裝載到IOC容器中
基於前面的分析,大家可以猜想到,自動裝配的核心是掃描約定目錄下的文件進行解析,解析後將得到的Configuration配置類通過ImportSelector進行導入,完成Bean的自動裝配。那麼我們下面仔細分析下AutoConfigurationImportSelector中的selectImport方法
AutoConfigurationImportSelector主要有兩個功能:
1.從META-INF/spring-autoconfigure-metadata.properties中加載自動裝配的條件元數據,簡單來說就是隻有滿足條件的Bean才能夠進行裝配
2.收集所有符合條件的配置類 antoConfigurationEntry.getConfiguration(),完成裝配
馬上就是核心加載過程了:看我的標記,下面介紹此方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
最最核心過程
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
當你看到這,其實你已經瞭解了大半,就剩下最後一個Boss需要你KO
----------------------------------------------------------------------------------------------------------------------------------------------------------------
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
//獲得@EnableAutoConfiguration註解中的屬性exclude excludeName等
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations =
//獲得所有自動裝配的配置類
this.getCandidateConfigurations(annotationMetadata, attributes);
//去除重複的配置項
configurations = this.removeDuplicates(configurations);
//根據@EnableAutoConfiguration註解中配置的exclude等屬性,把不需要的自動裝配的類去除
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
//廣播事件
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
總結:就是它獲取所有的配置類,通過去重、exclude排除等操作,得到最終需要實現自動裝配的配置類。這裏需要關注的就是getCandidateConfigurations 他是配置類 最核心 最核心 最核心 最核心
我說了4遍哦,的方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
這裏面用到了SpringFactoriesLoader,它是Spring內部提供的一種加載方式,就跟SPI 一樣,(SPI不懂的大家百度下,jdk spi dubbox spi)。簡單來說就是掃描classpath下的META-INF/spring.factories文件,其中spring.factories文件中的數據以key=value格式存儲,而這個加載器會根據key到到對應的value.