共计 2441 个字符,预计需要花费 7 分钟才能阅读完成。
1. 问题形容
最近在梳理我的项目中的基础设施模块,心愿将主动扫描(@ComponentScan)的形式,改为基于 @Configuration 的形式,这样在编写测试类的时候,可能有抉择的对基础设施相干的 Bean 进行拆卸。通过这样的梳理和思考,可能晋升模块的内聚性。
然而,在操作的过程中基于理论状况,认为某些 Bean 的 实例化 有先后顺序,因而想当然的认为可能通过 @Order 注解(或者 Ordered 接口)来实现 Bean 实例化的先后顺序。其实不然。
2. 问题剖析
咱们定义了如下 3 个 Bean。别离实现 Ordered 接口,并别离返回 3、2、1。按预期的成果,应该值越小,越先初始化。
@Slf4j
@Component
public class AOrderBean implements Ordered {public AOrderBean() {log.info("init AOrderBean");
}
@Override
public int getOrder() {return 3;}
}
@Slf4j
@Component
public class BOrderBean implements Ordered {public BOrderBean() {log.info("init BOrderBean");
}
@Override
public int getOrder() {return 2;}
}
@Slf4j
@Component
public class COrderBean implements Ordered {public COrderBean() {log.info("init COrderBean");
}
@Override
public int getOrder() {return 1;}
}
程序运行后果:
从运行后果剖析,Ordered 接口并没有达到预期的成果。
3. Order 排序的原理
通过剖析 Spring 源码,发现基于 Order 的程序性问题是通过 AnnotationAwareOrderComparator
实现的。该比拟器调用的中央,就是 Order 失效的中央。
4. Order 失效的场景
通过全局搜寻, 在 Spring 和 Spring Boot 我的项目中,有如下中央应用到了该类:
4.1 spring-context 模块
如上图所示,在 spring-context 模块中有如下接口对 Order 失效:
- Condition 接口
- DeferredImportSelector 导入内部拆卸配置
- ApplicationListener
- EventListenerFactory
- SchedulingConfigurer
4.2 spring-core 模块
如上如所示,SpringFactoriesLoader 按指定类型加载对应配置时,能够失效。全局搜寻该办法失去如下:
Spring Boot 在启动的时候对 spring.factories 中的相干配置进行读取时,就应用了该办法。
4.3 spring-test 模块
如上图所示:
- ApplicationContextInitializer
- TestExecutionListener
4.4 spring-web 模块
4.5 spring-boot
spring-boot 中能够被影响的有:
- ApplicationRunner
- CommandLineRunner
- ErrorViewResolver
- getSpringFactoriesInstances 办法调用的中央
- ApplicationListener
- FailureAnalyzer
- TypeSupplier
- ErrorPageRegistrar
- WebServerFactoryCustomizer
- ServletContextInitializer
5. 其余已知失效场景
5.1 @Aspect 注解
通过 @Aspect 对雷同的调用点进行加强时,当存在多个加强同时心愿管制其程序时,能够应用 @Order
5.2 拆卸汇合类型
@Component
public class FilterChain {
private List<Filter> filterList;
public FilterChain(List<Filter> filterList) {System.out.println(filterList.getClass().getSimpleName());
this.filterList = filterList;
}
@PostConstruct
public void init() {filterList.stream().map(Filter::getName).forEach(System.out::println);
}
}
如上述代码所示,通过汇合类型拆卸,将所有实现了 Filter 接口的 Bean,拆卸到 filterList 时,如果各个 Filter 对应的 Bean 实现了 @Order, 最终 List 中的 Bean 将时有序的。
5.3 PostProcessor
- BeanPostProcessor
- BeanFactoryPostProcessor
上述两类处理器,在主动拆卸的ApplicationContext
中通过实现 Ordered 接口,可能管制程序,然而对于 @Order 注解,暂不反对。
6. 论断
限于篇幅,上边的查找可能并不全面,比方并没有查找 AnnotationAwareOrderComparator
的父类 OrderComparator
的调用点。然而能够得出一个论断:
Order 并不能扭转 spring 实例化 Bean 的程序。只能扭转 Bean 运行程序。因而,在理论配置中,Bean 之间的拆卸,依赖 spring 的默认拆卸机制来保障。对于间接依赖,能够通过 @DependsOn 注解进行微调。
对于 spring boot 的 *AutoConfiguration
来说,能够通过
- @AutoConfigureBefore
- @AutoConfigureAfter
- @AutoConfigureOrder
来进行拆卸程序的管制。该形式在基于扫描拆卸下的 @Configuration 模式,并不失效。