SpringBoot學習(三)

spring.factories文件以及@EnableAutoConfiguration開啓自動配置詳解

在閱讀spring-boot相關源碼時,經常見到spring.factories文件,裏面寫了自動配置(AutoConfiguration)相關的類名,所以產生了一個疑問:「明明自動配置的類已經打上了@Configuration的註解,爲何還要寫spring.factories文件?」spring

這個話題須要從@SpringBootApplication註解開始提及。ide

查看@SpringBootApplication源碼,咱們能看到繼承的如下註解:spring-boot

@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 {
    ……
}

其中比較重要的是@EnableAutoConfiguration和@ComponentScan兩個註解。@ComponentScan註解的做用是掃描@SpringBootApplication所在的Application類(即spring-boot項目的入口類)所在的包(basepackage)下全部的@component註解(或拓展了@component的註解)標記的bean,並註冊到spring容器中。this

看到這裏也許會有個疑問,在spring-boot項目中pom文件裏面添加的依賴中的bean(spring-boot項目外的bean)是如何註冊到spring-boot項目的spring容器中的呢?spa

這就須要討論@EnableAutoConfiguration的做用。查看@EnableAutoConfiguration源碼,.net

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}

 

咱們能夠看到比較關鍵的代碼是@Import(AutoConfigurationImportSelector.class),而AutoConfigurationImportSelector.class作了什麼呢?經過其源碼能夠看出關鍵的部分爲,code

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
            .loadMetadata(this.beanClassLoader);
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
            annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

 

其中,getAutoConfigurationEntry方法獲取了spring-boot項目中須要自動配置的項(bean),查看其源碼發現,component

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
        AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = filter(configurations, autoConfigurationMetadata);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

 

其中最重要的部分爲getCandidateConfigurations方法,它獲取了全部可能參與到項目的候選配置bean,與之對應的,getExclusions獲取了全部不須要加載的配置bean。進一步查看getCandidateConfigurations方法的源碼,blog

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
            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;
}

這個方法的具體實現爲,讀取spring-boot項目的classpath下META-INF/spring.factories的內容,這個文件經常以K/V的形式存儲數據,例如:繼承

# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.HelloAutoConfiguration,\
……

 

getCandidateConfigurations方法獲取須要自動配置的類,除去上面講到的須要排除(exclude)的配置類,其餘類將會註冊到spring-boot項目的spring容器中。

看到這裏,想必已經瞭解@EnableAutoConfiguration註解的工做原理,回到最初的話題,「爲何要寫spring.factories文件?」

結合前面提出的疑問——「在spring-boot項目中pom文件裏面添加的依賴中的bean是如何註冊到spring-boot項目的spring容器中的呢?」,不可貴出spring.factories文件是幫助spring-boot項目包之外的bean(即在pom文件中添加依賴中的bean)註冊到spring-boot項目的spring容器的結論。因爲@ComponentScan註解只能掃描spring-boot項目包內的bean並註冊到spring容器中,所以須要@EnableAutoConfiguration註解來註冊項目包外的bean。而spring.factories文件,則是用來記錄項目包外須要註冊的bean類名。原文連接:https://blog.csdn.net/SkyeBeFreeman/article/details/96291283

相關文章
相關標籤/搜索