本文是基於《Spring cloud Alibaba微服務原理與實戰》(作者:譚鋒)一書中關於SpringBoot的自動裝配原理學習了解的。
1、springBoot自動裝配的實現
通過IDEA創建一個SpringBoot工程后(或其他方式),就會在主啟動類的上方發現@SpringBootApplication這個注解,其實這個注解就像是一個封裝的方法。要進入到該注解中去,會發現有一個@EnableAutoConfiguration注解,見名知意,@EnableAutoConfiguration就是用來開啟SpringBoot的自動裝配的注解。
1 @SpringBootApplication 2 public class StaterApplication { 3
4 public static void main(String[] args) { 5 SpringApplication.run(StaterApplication.class, args); 6 } 7
8 }
9 @Target({ElementType.TYPE}) 10 @Retention(RetentionPolicy.RUNTIME) 11 @Documented 12 @Inherited 13 @SpringBootConfiguration 14 @EnableAutoConfiguration 15 @ComponentScan( 16 excludeFilters = {@Filter( 17 type = FilterType.CUSTOM, 18 classes = {TypeExcludeFilter.class} 19 ), @Filter( 20 type = FilterType.CUSTOM, 21 classes = {AutoConfigurationExcludeFilter.class} 22 )} 23 ) 24 public @interface SpringBootApplication { 25 .... 26 }
接着再進入@EnableAutoConfiguration,有兩個重要的注解
①、@AutoConfigurationPackage : 作用是把使用了該注解的類所在包以及子包下的所有組件掃描到spring IOC容器中 這也是為什么在創建SpringBoot項目時,一定要把controller、service等都要與主啟動類放在同一級目錄的原因。
②、@Import({AutoConfigurationImportSelector.class}) 這個注解才是自動裝配的重點,AutoConfigurationImportSelector這個類會實現配置類的導入,導入方式與@Configuration有一定的區別。
AutoConfigurationImportSelector實現了ImportSelector,它只有一個selectImports方法,返回一個String[]數組,這個數組中可以指定需要裝配到IOC容器的類,當在@Import中導入一個ImportSelector的實現類之后,會把該實現類中返回的Class都裝配到IoC容器中。和@Configuration不同的是,ImportSelector可以實現批量裝配,並且還可以通過邏輯處理來實現Bean的選擇性裝配,也就是很具上下文環境來決定哪些類能夠被IoC初始化。
1.1簡單使用ImportSelector
首先創建兩個類,要把這兩個類裝配到Ioc容器中
public class FirstClass{ } public class SecondClass{ }
創建一個ImportSelector的實現類,把上述定義的兩個Bean加入到String數組,意味着兩個Bean會裝配到Ioc中
自定義一個注解,模擬@EnableAutoConfiguration,通過@Import導入GpImportSelector.
創建一個啟動類,在該類上使用@EnableAutoImport注解后,就可以從Ioc容器中取得FirstClass對象的實例。
這種實現方式相比@Import(*Configuration.class)的好處在於裝配的靈活性,還可以實現批量裝配,比如在G平ImportSelector還可以直接在String數組中定義多個Configuration類,由於一個配置代表的是某一個組件中批量的Bean聲明,所以自動裝配過程中只需要掃描到指定路徑下的配置類即可。
2、自動裝配原理分析
定位到AutoConfigurationImportSeletor中的selectImpots方法,他是ImportSelector的實現,該方法主要有兩個功能:
①、AutoConfigurationMetadataLoader.loadMetadata從META-INFO/spring-autoconfigure-metadata.properties中加載自動裝配的條件的元數據,就是滿足條件的Bean才能夠進行裝配。
②、autoConfigurationEntry.getConfigurations()收集所有符合條件的配置類,完成自動裝配
需要注意的是,AutoConfigurationImportSeletor中不執行selectImports方法,而是通過ConfigurationClassPostProcessor中的processConfigBeanDefinitions方法來掃描和注冊所有的配置類的Bean,最終調用getAutoConfigurationEntry方法來獲得所有需要自動裝配的配置類。
以下是getAutoConfigurationEntry方法中幾個重要的方法:
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);//獲得@EnableAutoConfiguration注解的屬性exclude、excludeName等
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);//獲得候選的自動裝配的配置類
configurations = this.removeDuplicates(configurations);//去除重復配置項
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);//根據@EnableAutoConfiguration注解的屬性exclude等屬性,把不需要自動裝配的移除
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
總的來說就是,先獲取所有的配置類,通過去重、exclude排除等操作,得到最終需要自動裝配的配置類。
getCandidateConfigurations這個方法中使用到了SpringFactoriesLoader,會掃描classpath下的META-INFO/spring.factories文件,spring.factories文件中的數據以key=value形式存儲,而SpringFactoriesLoader.loaderFactoryName會根據Key得到對應的value值,因此,key對應為EnableAutoConfiguration,Value是多個配置類,也就是getCandidateConfigurations返回的值。
省略。。。。。
另外還使用了許多@ConditionXXX的條件裝配的注解
至此,自動裝配的原理就分析完了,簡單總結一下:
①、通過@Import(AutoConfigurationImportSelector.class),導入配置類,這里並不是單個配置類的導入
②、AutoConfigurationImportSelector實現了ImportSelector類,重寫了selectImports方法,用於實現選擇性的批量配置類的裝配
③、通過Spring的SpringFactoryLoader機制,掃描classpath下的META/spring.factories文件,讀取需要實現自動裝配的配置類
④、通過條件篩選,把不符合的移除,最終實現自動裝配