@Configuration 配置類排序


(version: SpringBoot 2.2.2.RELEASE)

SpringBoot 會對 spring.factories 中的 @Configuration 類進行排序。
注意:只是對所有 spring.factories 中的 @Configuratin 類排序(也就是通常使用的 starter 里面的配置)

排序使用的注解有:@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter
也就是說,@AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter 這三個注解只對 spring.factories 中的 @Configuration 類生效

 

org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping#getImports()

1 public Iterable<Group.Entry> getImports() {
2     for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
3         // 1. 通過 ImportSelector 加載所有待解析的 @Configuration 類
4         this.group.process(deferredImport.getConfigurationClass().getMetadata(),deferredImport.getImportSelector());
5     }
6     // 2. 獲取排序過的 @Configuration 類
7     return this.group.selectImports();
8 }

 

1. org.springframework.context.annotation.DeferredImportSelector.Group#process()
    1.1 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry()
        1.1.1 org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames() // 加載所有 spring.factories 中的類
2. org.springframework.context.annotation.DeferredImportSelector.Group#selectImports()
    2.1 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#sortAutoConfigurations() // 對 spring.factories 中的 @Configuration 類進行排序
        2.1.1 org.springframework.boot.autoconfigure.AutoConfigurationSorter#getInPriorityOrder() // 對 @Configuration 類進行排序

 

org.springframework.boot.autoconfigure.AutoConfigurationSorter#getInPriorityOrder()

 1 List<String> getInPriorityOrder(Collection<String> classNames) {
 2     AutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory,
 3             this.autoConfigurationMetadata, classNames);
 4     List<String> orderedClassNames = new ArrayList<>(classNames);
 5     // Initially sort alphabetically
 6     // 1. 按字母順序排
 7     Collections.sort(orderedClassNames);
 8     // Then sort by order
 9     // 2. 按 @AutoConfigureOrder 排
10     orderedClassNames.sort((o1, o2) -> {
11         int i1 = classes.get(o1).getOrder();
12         int i2 = classes.get(o2).getOrder();
13         return Integer.compare(i1, i2);
14     });
15     // Then respect @AutoConfigureBefore @AutoConfigureAfter
16     // 3. 按 @AutoConfigureBefore @AutoConfigureAfter 排
17     orderedClassNames = sortByAnnotation(classes, orderedClassNames);
18     return orderedClassNames;
19 }

 

場景:
兩個配置類 AConfiguration 和 BConfiguration 都在 spring.factories 中,且兩個配置類中都會去加載同一個 bean ServiceA,且 ServiceA 是按條件加載的(@ConditionalOnMissingBean(ServiceA.class))。現在 AConfiguration 中的 ServiceA 總是優先處理,從而加載了 AConfiguration 中的 ServiceA。而我現在想讓 BConfiguration 中的 ServiceA 優先注冊。
解決辦法:
通過 @AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter 來調整 BConfiguration 的處理順序,讓它優先處理


實際場景:(springboot 多 context-path 支持時遇到的問題)
spring-boot-autoconfigure-2.2.2.RELEASE.jar 會自動加載 ServletWebServerFactoryAutoConfiguration,它會去加載配置類 ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,從而初始化一個 TomcatServletWebServerFactory 的 bean,它是帶條件加載的:@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)。
而我現在要在 FwEndpointConfiguration 自定義一個 TomcatServletWebServerFactory,按道理 spring-boot-autoconfigure-2.2.2.RELEASE.jar 中的 TomcatServletWebServerFactory 不應該被注冊,因為我自定義了一個 TomcatServletWebServerFactory,但是現實是往容器中注冊了兩個 TomcatServletWebServerFactory,最后報錯了。
原因是:
ServletWebServerFactoryAutoConfiguration 配置類的處理優先級高於 FwEndpointConfiguration,也就是說 EmbeddedTomcat 中的 TomcatServletWebServerFactory 往容器中注冊時,發現容器中還沒有 TomcatServletWebServerFactory 的 BeanDefinition,所以它就注冊進去了。
解決辦法:
將自定義的 FwEndpointConfiguration 的優先級調在 ServletWebServerFactoryAutoConfiguration 之前
注意:
ServletWebServerFactoryAutoConfiguration 本身是通過 spring.factories 加載的
前提是 FwEndpointConfiguration 在 spring.factories 中,才可以調整 FwEndpointConfiguration 的處理順序。
如果 FwEndpointConfiguration 不在 spring.factories 中,但是它是通過 spring.factories 中的 XxCofiguration 間接導入的,則需要調整 XxCofiguration 的順序即可


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM