Spring @Order注解无效?理解错@Order用途了吧

编程教程 > Java > Spring (58) 2025-04-21 14:35:34

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("AOrderBean created");
    }

    @Override
    public int getOrder() {
        return 3;
    }
}

@Slf4j
@Component
public class BOrderBean implements Ordered {

    public BOrderBean() {
        log.info("BOrderBean created");
    }

    @Override
    public int getOrder() {
        return 2;
    }
}

@Slf4j
@Component
public class COrderBean implements Ordered {

    public COrderBean() {
        log.info("COrderBean created");
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

程序运行结果:

Spring @Order注解无效?理解错@Order用途了吧_图示-6a7d3c9b10af4edab1f9195a12c3f3fc.png

从运行结果分析,Ordered 接口并没有达到预期的效果。

3. Order排序的原理

通过分析 Spring 源码,发现基于 Order 的顺序性问题是通过 AnnotationAwareOrderComparator 实现的。该比较器调用的地方,就是 Order 生效的地方。

Spring @Order注解无效?理解错@Order用途了吧_图示-7bb6f4548211440a81e7d21eb337d707.png

4. Order 生效的场景

通过全局搜索,在 Spring 和 Spring Boot 项目中,有如下地方使用到了该类:

4.1 Order在spring-context 模块使用情况

Spring @Order注解无效?理解错@Order用途了吧_图示-b7e6c4cab5fb459b9f4e97d9c502c93b.png

IDEA查看指定类在哪些地方用到快捷键-XQLEE'Blog

如上图所示,在spring-context模块中有如下接口对 Order 生效:

  • Condition 接口
  • DeferredImportSelector 导入外部装配配置
  • ApplicationListener
  • EventListenerFactory
  • SchedulingConfigurer

4.2 Order在spring-core 模块使用情况

Spring @Order注解无效?理解错@Order用途了吧_图示-09599e011eb3448d9c6a3edb0997ba27.png

如上如所示,SpringFactoriesLoader 按指定类型加载对应配置时,可以生效。

全局搜索该方法得到如下:

Spring @Order注解无效?理解错@Order用途了吧_图示-039038a2bf114e6a802c5fce4bb63150.png

注意:spring boot 3.x已经弃用spring.factories了

4.3 Order在spring-webmvc  模块使用情况

Spring @Order注解无效?理解错@Order用途了吧_图示-2fb74d3360624c7fafdb2237e8bd6d3a.png

 

5. 其他已知Order生效场景

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 模式,并不生效。

 

 

 


评论
User Image
提示:请评论与当前内容相关的回复,广告、推广或无关内容将被删除。

相关文章
1. 问题描述最近在梳理项目中的基础设施模块,希望将自动扫描(@ComponentScan)的方式,改为基于 @Configuration 的方式,这样在编写测
Spring框架中注解@PostConastruct 和 @PreDestroy来实现Bean初始化和销毁时候执行方法
案例需求配置示例version: "3.8"networks: demoRouter:services: demo-mysql8: image: mysql:8
Docker MySQL官方镜像启动默认初始化创建数据库,docker MySQL初始化sql脚本执行,初始化用户sql脚本version: "3.8"netw
spring boot RedisTemplateHelper import org.springframework.context.annotation.Bean; import org.s...
通过之前的一些文章spring boot 2.3 hibernate validate框架未引入-xqlee (blog.xqlee.com)Spring boot 参数分组校验-xqlee (...
Spring Context 与Spring MVC Context那些坑
了解Spring bean 生命周期。我们将了解 bean生命周期阶段、初始化和销毁​​回调方法。我们将学习使用 XML 配置以及 Java 注释配置来自定义 bean 生命周期事件。1. 什么...
常见优化技术我们先从工业实践角度总结,几条常见 MySQL 查询优化策略。索引优化为常用的查询条件(WHERE、JOIN、GROUP BY、ORDER BY)添
Spring Boot 通过Filter添加logback traceId@Slf4j@Componentpublic class TraceIdFilter
Spring Boot 2.1 新特性,已升级Spring 版本为5.1,支持servlet 4.0,支持Tomcat 9.0等等
spring mvc采用mapping代码方式配置项目的默认首页注意事项,spring mvc,默认首页,spring
Spring Boot 2.0,Spring框架的Spring Boot 中的Spring Boot Actuator变化讲解。并且了解如何在Spring Boot 2.0中使用Actuator...