Springboot @Configuration與自動配置詳解
不知道大家第一次搭SpringBoot環(huán)境的時候,有沒有覺得非常簡單。無須各種的配置文件,無須各種繁雜的pom坐標(biāo),一個main方法,就能run起來了。與其他框架整合也賊方便,使用EnableXXXXX注解就可以搞起來了!
所以今天來講講SpringBoot是如何實現(xiàn)自動配置的~
@SpringBootApplication: Spring Boot應(yīng)用標(biāo)注在某個類上說明這個類是SpringBoot的主配置類,SpringBoot需要運行這個類的main方法來啟動SpringBoot應(yīng)用;
先看一下@SpringBootApplication注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {
注解說明:
@SpringBootCon?guration:
Spring Boot的配置類;標(biāo)注在某個類上,表示這是一個Spring Boot的配置類(對@Con?guration做了繼承,目的只是標(biāo)識是springboot的配置類);
@EnableAutoCon?guration:
開啟自動配置功能的關(guān)鍵注解,就是通過這個注解把所需的bean自動裝配到spring容器中。
再看一下這個注解:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {
其中有一個通過@Import注解導(dǎo)入了一個重要的對象AutoConfigurationImportSelector,它實現(xiàn)了DeferredImportSelector接口,
關(guān)于這個接口的的作用是延遲導(dǎo)入所有自動裝配的BeanDefinition,把這些BeanDefinition和生成的bean對比其它的bean是放在最后導(dǎo)入,這樣后面使用springboot封裝的@ConditionalOnBean、@ConditionalOnMissingBean 、@ConditionalOnClass、@ConditionalOnMissingClass、@ConditionalOnProperty判斷這個類需不需要裝配具有前提條件。
例如:如果我們自己在項目中配置類mybatis的SqlSessionFactory對象,則springboot中則不會再進(jìn)行自動裝配,
自定義
@Bean
Public SqlSessionFactory getSqlSessionFactory (){
…
Return sqlSessionFactory ;
}
再看一下AutoConfigurationImportSelector對象:
其實現(xiàn)了延遲導(dǎo)入bean的接口DeferredImportSelector
這個可以往spring容器中注入對象。
String[] selectImports(AnnotationMetadata annotationMetadata) 此方法是在public Class<? extends Group> getImportGroup() 方法返回null的情況下,才執(zhí)行生效的。否則不生效,所以此方法不做特別講解。
主要看實現(xiàn)的方法:
@Override public Class<? extends Group> getImportGroup() { return AutoConfigurationGroup.class; }
在spring中會執(zhí)行AutoConfigurationGroup類的process方法,先分析此方法的作用:
@Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); //在此方法中找到候選自動轉(zhuǎn)入的bean的class的name。 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); } }
此方法的作用是找出所有候選的需要自動裝配bean的class對象名字;都封裝在AutoConfigurationEntry對象中,然后裝入全局變量中待后面方法的使用。
看一下如何找到候選待裝配的bean,調(diào)用下面的方法:
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } //此方法就是獲取注解中設(shè)置的排除裝配的bean AnnotationAttributes attributes = getAttributes(annotationMetadata); //此方法就是獲取所有的候選的bean List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); //根據(jù)名稱去重 configurations = removeDuplicates(configurations); //獲取排除的Bean Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); //進(jìn)行排除 configurations.removeAll(exclusions); //這一步也是比較重要的,就是根據(jù)那些@Condition注解從候選的class中選擇符合條件的 configurations = getConfigurationClassFilter().filter(configurations); //執(zhí)行自動導(dǎo)入的監(jiān)聽事件AutoConfigurationImportListener fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
那如何獲取到合適的class的呢?
1、是獲取項目中(pom.xml導(dǎo)入jar包)META-INF/spring.factories文件中配置的的所有key-value
2、所以找到Map<String, List>類型的數(shù)據(jù);
3、根據(jù)可以org.springframework.boot.autoconfigure.EnableAutoConfiguration作為key找到其中的List數(shù)據(jù);
4、這些就是所有候選的class的名字
如下就是候選的class
configurations = getConfigurationClassFilter().filter(configurations);
這一步是根據(jù)候選class中的以@Condition開頭注解來過濾合適的自動裝配的bean。
先獲取三個如果所示的過濾器對象;然后傳入所有候選的class名字進(jìn)行過濾,返回合適的自動裝配的bean,以mybatis為例:
根據(jù)這些條件進(jìn)行過濾是否裝入bean;
最后一List返回所有符合條件的配置類;也會在list組內(nèi)進(jìn)行排序:根據(jù)@Order、@AutoConfigureAfter、@AutoConfigureBefore注解進(jìn)行排序
AutoConfigurationGroup#selectImports
我們可以看到過濾完之后,只剩下少量作為的對象作為配置類;
總結(jié):
Spring自動裝配的原理是:
1、通過延遲導(dǎo)入bean的對象DeferredImportSelector批量的把符合條件的配置類class名稱進(jìn)行返回;
2、然后根據(jù)上步返回的class名稱,也就是組件的配置類全限定名,把組件的配置對象裝配到spring容器中;
3、而springboot篩選合適的組件配置類是通過獲取META-INF/spring.factorys文件下key為org.springframework.boot.autoconfigure.EnableAutoConfiguration
的calss名稱value只集合,然后根據(jù)這些class上面的相關(guān)以@ConditionalOn
開通的注解來過濾正在的配置類的class名稱進(jìn)行返回。
@xxxConditional根據(jù)當(dāng)前不同的條件判斷,決定這個配置類是否生效?
@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必須是@Conditional指定的條件成立,才給容器中添加組件,配置配里面的所有內(nèi)容才生效;
到此這篇關(guān)于Springboot @Configuration與自動配置詳解的文章就介紹到這了,更多相關(guān)Springboot @Configuration內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java數(shù)據(jù)結(jié)構(gòu)與算法之插入算法實現(xiàn)數(shù)值排序示例
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)與算法之插入算法實現(xiàn)數(shù)值排序的方法,結(jié)合簡單實例形式分析了插入算法的節(jié)點操作與排序相關(guān)實現(xiàn)技巧,需要的朋友可以參考下2016-08-08Springboot項目實現(xiàn)Mysql多數(shù)據(jù)源切換的完整實例
這篇文章主要給大家介紹了關(guān)于Springboot項目實現(xiàn)Mysql多數(shù)據(jù)源切換的完整實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Spring Boot使用JSR-380進(jìn)行校驗的示例
這篇文章主要介紹了Spring Boot使用JSR-380進(jìn)行校驗,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03springboot集成junit編寫單元測試實戰(zhàn)
在做單元測試時,代碼覆蓋率常常被拿來作為衡量測試好壞的指標(biāo),本文主要介紹了springboot集成junit編寫單元測試實戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02