zoukankan      html  css  js  c++  java
  • @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 的顺序即可

  • 相关阅读:
    【HDOJ】2267 How Many People Can Survive
    【HDOJ】2268 How To Use The Car
    【HDOJ】2266 How Many Equations Can You Find
    【POJ】2278 DNA Sequence
    【ZOJ】3430 Detect the Virus
    【HDOJ】2896 病毒侵袭
    求奇数的乘积
    平方和与立方和
    求数列的和
    水仙花数
  • 原文地址:https://www.cnblogs.com/kevin-yuan/p/12431791.html
Copyright © 2011-2022 走看看