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 的顺序即可

  • 相关阅读:
    如何查看IIS的80端口被占用? 拂晓风起
    配置VSS2005(在局域网内搭建服务器) 拂晓风起
    Log4Net ,.net和SQL Server的完美结合 拂晓风起
    SQL Server简单使用配置 拂晓风起
    ztree图标不显示
    oracle添加同义词
    Struts2作用域和标签库(转)
    java实现链表(转)
    unexpected end of subtree(hql拼写有误,仔细查看hql语句,以及参数值的导入)
    http://www.mianwww.com/html/2012/10/17027.html面试题(经典)
  • 原文地址:https://www.cnblogs.com/kevin-yuan/p/12431791.html
Copyright © 2011-2022 走看看