当前位置: 首页 > 后端技术 > Java

Spring@Order注解,你可能理解错了

时间:2023-04-01 18:13:53 Java

1。问题描述最近在整理项目中的基础模块,希望能把自动扫描(@ComponentScan)方式改为@Configuration-based方式,这样在写测试类的时候,可以有选择性的组装相关的bean基础设施。通过这样的整理和思考,可以提高模块的内聚性。但是在运行的过程中,根据实际情况,认为有些bean的实例化是有顺序的,所以理所当然的认为bean实例化的顺序可以通过@Order注解(或者Ordered界面)。其实并不是。2.问题分析我们定义了以下三个bean。实现Ordered接口,分别返回3、2、1。根据预期的效果,值越小,初始化越早。@Slf4j@ComponentpublicclassAOrderBeanimplementsOrdered{publicAOrderBean(){log.info("initAOrderBean");}@OverridepublicintgetOrder(){返回3;}}@Slf4j@ComponentpublicclassBOrderBeanimplementsOrdered{publicBOrderBean(){log.info("initBOrderBean");}@OverridepublicintgetOrder(){返回2;}}@Slf4j@ComponentpublicclassCOrderBeanimplementsOrdered{publicCOrderBean(){log.info("initCOrderBean");}@OverridepublicintgetOrder(){返回1;}}程序运行结果:从运行结果分析,Ordered接口没有达到预期的效果。3、Order排序的原理通过分析Spring源码发现,基于Order的排序问题是通过AnnotationAwareOrderComparator实现的。调用比较器的地方就是Order生效的地方。4.全局搜索订单生效场景。在Spring和SpringBoot项目中,这个类用在了以下几个地方:4.1spring-context模块如上图所示。在spring-context模块中,以下接口对Order生效:Condition接口DeferredImportSelector导入外部程序集配置ApplicationListenerEventListenerFactorySchedulingConfigurer4.2spring-core模块如上图,当SpringFactoriesLoader根据指定类型加载相应配置时,即可生效.全局搜索该方法如下:SpringBoot在启动时读取spring.factories中的相关配置时使用该方法。4.3spring-test模块如上图所示:ApplicationContextInitializerTestExecutionListener4.4spring-web模块4.5spring-bootspring-boot中可以被影响的有:ApplicationRunnerCommandLineRunnerErrorViewResolvergetSpringFactoriesInstances方法调用的地方ApplicationListenerFailureAnalyzerTypeSupplierErrorPageRegistrarWebServerFactoryCustomizerServletContextInitializer5.其他已知生效场景5.1@Aspect注解通过@Aspect对Whenthesamecallpointisenhanced,whentherearemultipleenhancementsandyouwanttocontroltheirorder,youcanuse@Order5.2assemblycollectiontype@ComponentpublicclassFilterChain{privateListfilterList;publicFilterChain(ListfilterList){System.out.println(filterList.getClass().getSimpleName());this.filterList=filterList;}@PostConstructpublicvoidinit(){filterList.stream().map(Filter::getName).forEach(System.out::println);}}Asshownintheabovecode,whenassemblingallbeansthatimplementtheFilterinterfaceintothefilterListthroughassemblytypeassembly,ifthebeanscorrespondingtoeachFilterimplement@Order,thefinalBeanintheListwillbeinorder.5.3PostProcessorBeanPostProcessorBeanFactoryPostProcessor以上两类处理器可以通过在自动组装的ApplicationContext中实现Ordered接口来控制顺序,但是目前不支持@Order注解。6.结论限于篇幅,以上搜索可能不全面。例如,找不到AnnotationAwareOrderComparator的父类OrderComparator的调用点。但是可以得出一个结论:顺序不能改变spring实例化bean的顺序。只能更改bean运行的顺序。所以在实际配置中,bean之间的组装是通过spring默认的组装机制来保证的。对于间接依赖,可以通过@DependsOn注解进行微调。对于springboot的*AutoConfiguration,组装顺序可以通过@AutoConfigureBefore@AutoConfigureAfter@AutoConfigureOrder来控制。该方法在基于扫描组件的@Configuration模式下不生效。