springboot的自動配置

1. 原由

​ 使用springboot也有些時間,一直很好奇它如何作到自動配置的,因此查閱了相關資料而且學習了相關內容,才寫了這篇文章。java

2. 分析

​ ①第一步咱們從它的啓動配置類(XxxApplication)收起,咱們進入到他的@SpringBootApplication註解。
在這裏插入圖片描述spring

​ ②咱們能夠看到以下代碼,因爲咱們須要找到致使它自動配置的,因此鎖定了@EnableAutoConfiguration註解,那麼就能夠進入這個註解。springboot

@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 {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};
}

在這裏插入圖片描述

​ ③ 咱們看到了以下代碼,因爲這是一個接口,而它的實現類咱們又很差肯定,因此咱們只好從註解入手,因爲@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited等都是元註解,咱們能夠從@AutoConfigurationPackage,@Import({AutoConfigurationImportSelector.class})中找到咱們想要的,根據它的中文意思咱們能夠從@Import({AutoConfigurationImportSelector.class})(自動有選擇的導入配置)出發,畢竟不是全部的配置都會都如,而導入那些配置根據項目中使用了那些starter決定。
在這裏插入圖片描述app

​ ④點入第三步提到的註解,進入這個類根據方法名咱們能夠猜想是和這個方法相關,經過閱讀這個代碼,咱們能夠猜想是和getAutoConfigurationEntry這個方法有關,因此不妨點進去。學習

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());
        }
    }

​ ⑤因爲咱們須要的配置Config,因此大體能夠判定是和這個代碼有關聯List configurations = this.getCandidateConfigurations(annotationMetadata, attributes); ,因此不妨進到這個getCandidateConfigurations方法中去。this

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            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);
        }
    }

​ ⑥通過第五步,咱們能夠看到以下代碼code

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;
    }

不妨看這部分代碼,List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); ,它的意思是一個加載器經過加載某個工廠得到配置的List,所以咱們在進入到這個的實現是沒有必要的,能夠從參數考慮,因此鎖定在第一個參數,點進入能夠看到以下代碼。xml

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }

看到這裏可能仍是會疑惑?爲啥就自動配置了,其實咱們這個方法(loadFactoryNames)是從一個配置文件中讀取內容,它的鍵是EnableAutoConfiguration,而這個配置文件是在如圖所示的文件中。blog

在這裏插入圖片描述
在這裏插入圖片描述

⑥打開上述文件,根據上一步的鍵找它的值,如圖就是springboot配置類,那麼項目啓動時是否是全部的配置都起做用嗎?不妨進入到某個配置類查看便可。如圖所示的@ConditionalOnMissingBean註解表示項目的容器是否有這個bean,若是沒有這個配置類就不會其做用,另外咱們只要在仔細看這個類首先進行了初始化,以後它會從配置文件(application.xml或者application.yml)中獲取值。
在這裏插入圖片描述接口

注:若有錯誤,歡迎指出。

相關文章
相關標籤/搜索