深入理解Spring的@Order注解和Ordered接口

2023-05-16

前言

  Spring的@Order注解或者Ordered接口大家都知道是控制顺序的,那么它们到底是控制什么顺序的?是控制Bean的注入顺序,还是Bean的实例化顺序,还是Bean的执行顺序呢?那么我们先直接给出结论再来验证结论。
结论:Spring的@Order注解或者Ordered接口,不决定Bean的加载顺序和实例化顺序,只决定Bean的执行顺序。

实例论证:@Order不决定Bean的加载和实例化顺序

步骤一:创建DemoService接口和三个实现类,分别打上注解@Order(0)-DemoServiceImpl01、@Order(1)-DemoServiceImpl02、@Order(2)-DemoServiceImpl03,观察实例化顺序。

@Service
@Order(0)
public class DemoServiceImpl01 implements DemoService {

    public DemoServiceImpl01() {
        System.out.println("DemoServiceImpl01被实例化了");
    }
}

@Service
@Order(1)
public class DemoServiceImpl02 implements DemoService {

    public DemoServiceImpl02() {
        System.out.println("DemoServiceImpl02被实例化了");
    }

}

@Service
@Order(2)
public class DemoServiceImpl03 implements DemoService {

    public DemoServiceImpl03() {
        System.out.println("DemoServiceImpl03被实例化了");
    }

}

// 运行结果如下
DemoServiceImpl01被实例化了
DemoServiceImpl02被实例化了
DemoServiceImpl03被实例化了

步骤二:改变DemoService接口三个实现类的注解序值,@Order(2)-DemoServiceImpl01、@Order(1)-DemoServiceImpl02、@Order(0)-DemoServiceImpl03,观察实例化顺序

@Service
@Order(2)
public class DemoServiceImpl01 implements DemoService {

    public DemoServiceImpl01() {
        System.out.println("DemoServiceImpl01被实例化了");
    }
}

@Service
@Order(1)
public class DemoServiceImpl02 implements DemoService {

    public DemoServiceImpl02() {
        System.out.println("DemoServiceImpl02被实例化了");
    }

}

@Service
@Order(0)
public class DemoServiceImpl03 implements DemoService {

    public DemoServiceImpl03() {
        System.out.println("DemoServiceImpl03被实例化了");
    }

}

// 运行结果如下
DemoServiceImpl01被实例化了
DemoServiceImpl02被实例化了
DemoServiceImpl03被实例化了

结果:当改变DemoService接口的三个实现类注解序值时,类的加载和实例化顺序根本没有变化,即@Order注解不决定Bean的加载和实例化顺序。

实例论证:@Order决定Bean的执行顺序

步骤一:创建RunServiceImpl类,并通过构造函数依赖注入DemoService的三个实现类,且循序依次执行三个实现类方法,观察Bean的执行顺序。

@Service
public class RunServiceImpl implements RunService {

    public RunServiceImpl(List<DemoService> demoServices) {
        demoServices.forEach(demoService -> demoService.say());
    }

}

@Service
@Order(0)
public class DemoServiceImpl01 implements DemoService {

    public DemoServiceImpl01() {
        System.out.println("DemoServiceImpl01被实例化了");
    }

    @Override
    public void say() {
        System.out.println("DemoServiceImpl01被执行了");
    }
}

@Service
@Order(1)
public class DemoServiceImpl02 implements DemoService {

    public DemoServiceImpl02() {
        System.out.println("DemoServiceImpl02被实例化了");
    }

    @Override
    public void say() {
        System.out.println("DemoServiceImpl02被执行了");
    }

}

@Service
@Order(2)
public class DemoServiceImpl03 implements DemoService {

    public DemoServiceImpl03() {
        System.out.println("DemoServiceImpl03被实例化了");
    }

    @Override
    public void say() {
        System.out.println("DemoServiceImpl03被执行了");
    }

}

// 运行结果如下
DemoServiceImpl01被执行了
DemoServiceImpl02被执行了
DemoServiceImpl03被执行了

步骤二:改变DemoService接口三个实现类的注解序值,@Order(2)-DemoServiceImpl01、@Order(1)-DemoServiceImpl02、@Order(0)-DemoServiceImpl03,观察Bean的执行顺序。

@Service
public class RunServiceImpl implements RunService {

    public RunServiceImpl(List<DemoService> demoServices) {
        demoServices.forEach(demoService -> demoService.say());
    }

}

@Service
@Order(2)
public class DemoServiceImpl01 implements DemoService {

    public DemoServiceImpl01() {
        System.out.println("DemoServiceImpl01被实例化了");
    }

    @Override
    public void say() {
        System.out.println("DemoServiceImpl01被执行了");
    }
}

@Service
@Order(1)
public class DemoServiceImpl02 implements DemoService {

    public DemoServiceImpl02() {
        System.out.println("DemoServiceImpl02被实例化了");
    }

    @Override
    public void say() {
        System.out.println("DemoServiceImpl02被执行了");
    }

}

@Service
@Order(0)
public class DemoServiceImpl03 implements DemoService {

    public DemoServiceImpl03() {
        System.out.println("DemoServiceImpl03被实例化了");
    }

    @Override
    public void say() {
        System.out.println("DemoServiceImpl03被执行了");
    }

}

// 运行结果如下
DemoServiceImpl03被执行了
DemoServiceImpl02被执行了
DemoServiceImpl01被执行了

结果:当改变DemoService接口的三个实现类注解序值时,类的执行顺序也随之发生变化,即@Order决定Bean的执行顺序。

@Order注解或Ordered接口决定Bean的执行顺序原理分析

通过上面实例论证,大家应该清楚@Order注解或Ordered接口只是决定了Bean的执行顺序,那么Spring是如何在依赖注入时完成根据@Order注解或Ordered接口控制Bean执行顺序?
原理分析:
当通过构造函数或者方法参数注入进某个List<组件实现类>时,Spring的DefaultListableBeanFactory类会在注入时调用AnnotationAwareOrderComparator.sort(listA)帮我们去完成根据@Order或者Ordered接口序值排序。

备注:
AnnotationAwareOrderComparator是OrderComparator的子类,而OrderComparator实现比较器Comparator接口,AnnotationAwareOrderComparator.sort(listA)会调用父类sort方法,会根据@Order或者Ordered接口设置的int序值重写sort方法进行排序,值越小优先级越高。


我的专栏

  1. 设计模式
  2. 认证授权框架实战
  3. java进阶知识
  4. maven进阶知
  5. spring进阶知识
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入理解Spring的@Order注解和Ordered接口 的相关文章

  • AOP 使用 around 来避免执行方法

    我在代码中使用 Spring AOP 来拦截某个方法的执行 我正在尝试做的一个简化示例如下 public void someMethod does something Around execution someMethod public v
  • 将图像上传到 spring mvc 中的文件夹

    我尝试将图像上传到我的资源中的文件夹 resouces images demo jpg 但它无法运行 你能帮忙在春天上传到我的资源吗mvc 如果我上传到 C test demo jpg 没关系 我的样本 String filename Fi
  • Spring部署期间依赖注入问题

    我正在启动一个 Primefaces Spring Hibernate 项目 并且仍在学习如何正确处理这些组件 但就在此时 我面临着一个与 spring 依赖注入相关的问题 这让我很害怕 我已经在网上寻找答案两天了 但找不到我的代码有什么问
  • 无法在 Spring boot 中使用 @Valid 验证请求正文

    我想验证我的请求正文 Valid注解 但在 Spring Boot 中不起作用 我在 JAR 文件中有一个 Request 类 无法使用两个字段进行修改 其中一个字段的类型为对象 我的控制器类接受此类对象作为请求主体 当我将下面的 JSON
  • 用于多部分/表单数据的 POSTMAN

    如何将 POSTMAN 用于 Multipart form data 它具有自定义标头来测试我的控制器 该控制器采用 2 个文件作为参数 public controller MultipartFile files POST HTTP 1 1
  • 如何更改Spring-WS的“SOAP-ENV”默认前缀

    我使用 Spring WS 创建了一个 Web 服务 为了保持与旧系统的兼容性 我需要将命名空间前缀从SOAP ENV to soap 我知道SOAP ENV and soap只是命名空间前缀 只要它们引用正确的命名空间 http sche
  • Spring JTA 事务与 Websphere 的 JPA 和 jndi 数据源

    我有多个数据源和一个配置有 JPA 的数据库 我正在使用 websphere 7 我希望将所有这些数据源配置为全局事务 我正在使用下面的 spring 配置 但事务没有按预期的全局事务工作 如果一个数据库发生故障 则另一个数据库将被提交 这
  • Java+Spring:SEVERE Servletservice

    我不知道我出了什么问题listContacts在控制器中map put contactList contactService listContact 有人可以帮助我吗 严重 路径 test 上下文中 servlet dispatcher 的
  • Spring休眠异常

    当我启动 SpringMVC 时 出现以下异常 Apr 28 2012 6 08 23 PM org apache catalina core AprLifecycleListener init INFO The APR based Apa
  • ZonedDateTime 的 Jackson 反序列化问题

    我在反序列化我正在使用的服务期间使用的类中有以下字段 private ZonedDateTime transactionDateTime 我正在使用的服务可能会使用以下模式返回日期或日期时间 yyyy MM dd T HH mm ss SS
  • Spring Security 实体字段级安全

    我有一个 Spring MVC 应用程序 它提供了一个视图 其中显示了来自Customer实体 例如姓名 地址 电话号码等 该应用程序具有各种角色 例如ROLE USER and ROLE ADMIN 用户具有ROLE USER只能看到客户
  • Jackson序列化配置

    我在 Spring 3 MVC 应用程序中使用 Jackson JSON 为了不序列化每个日期字段 我创建了一个使用特定日期格式的自定义对象映射器 Component jacksonObjectMapper public class Cus
  • 必须指定 Spring Security 身份验证管理器 - 用于自定义过滤器

    我正在尝试创建自定义用户名密码身份验证过滤器 因为我需要验证来自两个不同来源的密码 我正在使用 Spring Boot 1 2 1 和 Java 配置 我在部署时遇到的错误是 Caused by org springframework be
  • Spring Boot处理实体继承

    我正在处理这个tutorial http blog netgloo com 2014 12 18 handling entities inheritance with spring data jpa 处理实体继承 我有扩展用户实体的个人和公
  • 如何为 Spring REST 服务生成 WADL

    您好 我正在使用 Spring 3 5 0 Release 我想为我的 Spring Rest 服务生成 WADL 它们在 Spring 中有什么功能可以让我轻松生成 WADL 您可以使用 Swagger SpringMVC 它会自动将符合
  • Spring 3.1 MVC - 表单处理工作流程最佳实践

    目前我正在尝试了解 Spring MVC 3 1 中表单提交 验证 错误处理的正确工作流程 不 我有一些问题 保留表单错误 通过重定向绑定模型的正确方法是什么 是否有内置方法 我还没有找到 我知道我可以使用 Spring 表单标签和 JSR
  • 在 Spring boot 中运行时指定 MongoDb 集合名称

    我试图在两个不同的微服务中重用现有的 EmployeeRepository 代码 见下文 以将数据存储在两个不同的集合中 在同一数据库中 Document collection employee public interface Emplo
  • 覆盖 SpringMVC 应用程序中的默认重定向 URL

    我有一个简单的 Spring MVC 应用程序 它将在某些控制器操作后将用户重定向到新页面 例如 Controller public class ResponseController RequestMapping value save me
  • 将 Mockito 模拟注入 Spring bean

    我想将 Mockito 模拟对象注入到 Spring 3 bean 中 以便使用 JUnit 进行单元测试 我的 bean 依赖项当前是通过使用注入的 Autowired私有成员字段上的注释 我考虑过使用ReflectionTestUtil
  • 我使用 jsp/jstl/spring 动态生成 css 和 js。如何将此结果放置在头部的链接标记中。不在头部的脚本标签中

    我在jsp中生成css 输出是 现在我在 jsp 中使用以下代码调用此代码 它有效并且输出是这样的

随机推荐