為什么我要寫spring.factories文件?

在閱讀spring-boot相關源碼時,常常見到spring.factories文件,里面寫了自動配置(AutoConfiguration)相關的類名,因此產(chǎn)生了一個疑問:“明明自動配置的類已經(jīng)打上了@Configuration的注解,為什么還要寫spring.factories文件?”

這個話題需要從@SpringBootApplication注解開始說起。

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

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

注意:分包情況下,只要與Application類所在的包下所有的@Component(包括@Configuration)標記的Bean都會注冊到spring容器中。

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

這就需要討論@EnableAutoConfiguration的作用。查看@EnableAutoConfiguration源碼,

@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做了什么呢?通過其源碼可以看出關鍵的部分為,

@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),查看其源碼發(fā)現(xiàn),

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方法的源碼,

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

這個方法的具體實現(xiàn)為,讀取spring-boot項目的classpath下META-INF/spring.factories的內(nèi)容,這個文件常常以K/V的形式存儲數(shù)據(jù),例如:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.test.TestConfig

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

看到這里,想必已經(jīng)了解@EnableAutoConfiguration注解的工作原理,回到最初的話題,“為什么要寫spring.factories文件?”

結合前面提出的疑問——“在spring-boot項目中pom文件里面添加的依賴中的bean是如何注冊到spring-boot項目的spring容器中的呢?”,不難得出spring.factories文件是幫助spring-boot項目包以外的bean(即在pom文件中添加依賴中的bean)注冊到spring-boot項目的spring容器的結論。由于@ComponentScan注解只能掃描spring-boot項目包內(nèi)的bean并注冊到spring容器中,因此需要@EnableAutoConfiguration注解來注冊項目包外的bean。而spring.factories文件,則是用來記錄項目包外需要注冊的bean類名。

————————————————

原文鏈接:https://blog.csdn.net/SkyeBeFreeman/article/details/96291283

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 8月17日,人生中第一個七夕當晚,我提出了分手。我說,我覺得你不喜歡我,我們也需要時間成長,分手吧。然后就是統(tǒng)統(tǒng)的...
    Mia米亞米閱讀 182評論 0 0
  • 不知從什么時候開始 一切都在悄悄的變化 你是你 我是我 它是它 看似平靜安逸的樣子 終究抵不過時間煮雨 風輕輕的說...
    NIGHT_ing閱讀 134評論 0 1
  • (壹) 想變成一只貓 這樣 出太陽的時候 ...
    星光島閱讀 355評論 4 12
  • 月光盈盈地偎依窗欞 晶瑩的眸光 溫柔了夜的孤寂 靜悄的心情 蘸著這皎皎的月色 以詩的情思 寫就一縷柔美的文字 沁潤...
    雨弦紗閱讀 246評論 0 4
  • 1 、通證不是代幣 Token 的原意是指“令牌、信令”。區(qū)塊鏈的 token被廣泛認識,歸功于以太坊及其訂立的 ...
    皓淵3311閱讀 719評論 0 0

友情鏈接更多精彩內(nèi)容