吊炸天的SpringBoot自動裝配原理剖析(附面試總結)

在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.

 

作爲一個帥氣的boy我很貼心如意的給大家準備了面試答案哦

通過@Import(AutoConfigurationImportSelector)實現配置類的導入,但是並不是傳統意義上的單個導入,而是批量

AutoConfigurationImportSelector類實現了ImportSelector接口,重寫了方法selectImports,用於實現批量裝配

通過spirng tigao de SpringFactoriesLoader機制,掃描classpath路徑下的META-INF/spring.factories 讀取需要實現自動裝配的配置類。

最終通過篩選的方式,把不符合的類提出,最終完成SpringBoot的自動裝配

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章