Spring(18) @Order注解介绍、使用、底层原理
目录
- 一、简介
- 二、List 注入使用示例
- 2.1 测试接口类
- 2.2 测试接口实现类1
- 2.3 测试接口实现类2
- 2.4 启动类(测试)
- 2.5 测试结果
- 场景一:
- 场景二:
- 三、CommandLineRunner 使用示例
- 3.1 接口实现类1
- 3.2 接口实现类2
- 3.3 测试结果
- 场景一:
- 场景二:
- 四、@Order失效场景
- 4.1 失效代码示例
- 4.2 执行结果
- 4.3 失效场景补救
- 五、@Order、@Priority底层原理
- 5.1 平平无奇的启动类
- 5.2 神奇的 run() 方法
- 5.3 开始排序的 callRunners() 方法
- 5.4 排序调用图
- 5.5 排序的根源 findOrder() 方法
一、简介
@Order
:是 spring-core
包下的一个注解。@Order 作用是定义 Spring IOC 容器中 Bean 的执行顺序。
注意: Spring 的 @Order 注解或者 Ordered 接口,不决定 Bean 的加载顺序和实例化顺序,只决定 Bean 注入到 List 中的顺序。
@Order 注解接受一个整数值作为参数,数值越小表示优先级越高。当存在多个具有 @Order 注解的组件时,Spring Boot将按照数值从小到大的顺序加载它们。
需要注意的是:
- @Order 注解只能用于标记 Spring 容器中的组件,而不适用于标记普通的类。因此,在使用 @Order 注解时,确保你的组件被正确地注册到 Spring 容器中。
- @Order 注解只决定Bean的注入顺序,并不保证实际执行的顺序。例如:在 Web 应用中,Filter 的执行顺序并不受 @Order 注解影响。如果需要确保 Filter 按照顺序执行,可以使用 FilterRegistrationBean 来设置 Filter 的顺序。
二、List 注入使用示例
包结构如下:
2.1 测试接口类
IOrderTest 接口中定义了一个 handle()
方法用于测试。
IOrderTest.java
/*** <p> @Title IOrderTest* <p> @Description @Order注解测试接口** @author ACGkaka* @date 2023/10/17 11:20*/
public interface IOrderTest {/*** 处理*/void handle();
}
2.2 测试接口实现类1
@Order注解测试实现类01 和 @Order注解测试实现类02 实现了 IOrderTest 接口,用于测试 @Order 的生效。
OrderTestImpl01.java
import com.demo.test.IOrderTest;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** <p> @Title OrderTestA* <p> @Description @Order注解测试实现类01** @author ACGkaka* @date 2023/10/17 11:18*/
@Order(1)
@Component
public class OrderTestImpl01 implements IOrderTest {public OrderTestImpl01() {System.out.println("=== OrderTestImpl01 constructor() ==");}@Overridepublic void handle() {System.out.println("=== OrderTestImpl01 handle() ===");}
}
2.3 测试接口实现类2
@Order注解测试实现类01 和 @Order注解测试实现类02 实现了 IOrderTest 接口,用于测试 @Order 的生效。
OrderTestImpl02.java
import com.demo.test.IOrderTest;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** <p> @Title OrderTestImpl02* <p> @Description @Order注解测试实现类02** @author ACGkaka* @date 2023/10/17 11:18*/
@Order(2)
@Component
public class OrderTestImpl02 implements IOrderTest {public OrderTestImpl02() {System.out.println("=== OrderTestImpl02 constructor() ===");}@Overridepublic void handle() {System.out.println("=== OrderTestImpl02 handle() ===");}
}
2.4 启动类(测试)
SpringbootDemoApplication.java
import com.demo.test.IOrderTest;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;import java.util.List;@SpringBootApplication
public class SpringbootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootDemoApplication.class, args);}@Beanpublic CommandLineRunner commandLineRunner(List<IOrderTest> list) {return args -> {System.out.println("=== CommandLineRunner ===");list.forEach(IOrderTest::handle);};}
}
2.5 测试结果
场景一:
@Order(1)
注解修饰 OrderTestImpl01.java@Order(2)
注解修饰 OrderTestImpl02.java
执行结果如下:
场景二:
@Order(1)
注解修饰 OrderTestImpl02.java@Order(2)
注解修饰 OrderTestImpl01.java
执行结果如下:
三、CommandLineRunner 使用示例
3.1 接口实现类1
CommandLineRunner01.java
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** <p> @Title CommandLineRunner01* <p> @Description @Order注解测试01** @author ACGkaka* @date 2023/10/17 11:20*/
@Component
@Order(1)
public class CommandLineRunner01 implements CommandLineRunner {@Overridepublic void run(String... args) {System.out.println("=== CommandLineRunner01 ===");}
}
3.2 接口实现类2
CommandLineRunner02.java
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** <p> @Title CommandLineRunner02* <p> @Description @Order注解测试02** @author ACGkaka* @date 2023/10/17 11:20*/
@Component
@Order(2)
public class CommandLineRunner02 implements CommandLineRunner {@Overridepublic void run(String... args) {System.out.println("=== CommandLineRunner02 ===");}
}
3.3 测试结果
场景一:
@Order(1)
注解修饰 CommandLineRunner01.java@Order(2)
注解修饰 CommandLineRunner02.java
执行结果如下:
场景二:
@Order(1)
注解修饰 CommandLineRunner02.java@Order(2)
注解修饰 CommandLineRunner01.java
执行结果如下:
四、@Order失效场景
失效场景: 在
@Configuration
里面通过@Bean
方式创建 Bean,在上面加 @Order 控制顺序是没有效果的。
4.1 失效代码示例
SpringbootDemoApplication.java
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;@SpringBootApplication
public class SpringbootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootDemoApplication.class, args);}@Order(2)@Beanpublic CommandLineRunner commandLineRunner01() {return args -> System.out.println("=== commandLineRunner01 ===");}@Order(1)@Beanpublic CommandLineRunner commandLineRunner02() {return args -> System.out.println("=== commandLineRunner02 ===");}
}
4.2 执行结果
由下图可知,虽然我们使用 @Order 注解明确声明要先执行 commandLineRunner02,但是并没有生效。
4.3 失效场景补救
在 @Order 注解失效的场景下,可以通过以下方式来控制顺序:
- 方式一: 可以通过具体实现类的方式创建 Bean,用
@Order
+@Component
注解修饰。 - 方式二: 可以通过 RegistrationBean 方式创建 Bean,用 setOrder 添加顺序。
- 方式三: filter 可以通过 FilterRegistrationBean 创建 filter 的 Bean,用 setOrder 添加顺序。
五、@Order、@Priority底层原理
看完 @Order 注解的时候,可能会疑惑 IOC 容器时如何通过 @Order 注解来控制程序的先后顺序的,接下来我们从源码层面看下,容器是如何加载的。
先说结论:
- @Order 底层是在 Bean 注入 IOC 容器之后执行的,所以无法控制 Bean 的加载顺序。
- @Order 底层是通过 List.sort(Comparator) 实现的,AnnotationAwareOrderComparator 类集成 OrderComparator 类,通过获取注解的 value 值实现了比对逻辑。
5.1 平平无奇的启动类
SpringbootDemoApplication.java
@SpringBootApplication
public class SpringbootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootDemoApplication.class, args);}
}
5.2 神奇的 run() 方法
SpringApplication.run()
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);prepareContext(context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);// #### 重点!!!调用具体的执行方法 ###callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;
}
5.3 开始排序的 callRunners() 方法
SpringApplication.callRunners()
private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList<>();runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());// ### 重点!!!按照定义的优先级顺序排序 ###AnnotationAwareOrderComparator.sort(runners);for (Object runner : new LinkedHashSet<>(runners)) {if (runner instanceof ApplicationRunner) {callRunner((ApplicationRunner) runner, args);}if (runner instanceof CommandLineRunner) {callRunner((CommandLineRunner) runner, args);}}
}
5.4 排序调用图
由于剩下的实现内容调用链比较长,为了看起来更清晰直观,采用顺序图展现出来:
5.5 排序的根源 findOrder() 方法
获取 @Order 注解的 value 值,来进行排序。
OrderUtils.findOrder()
@Nullable
private static Integer findOrder(MergedAnnotations annotations) {MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);if (orderAnnotation.isPresent()) {// ### 重点!!!获取@Order注解的value值return orderAnnotation.getInt(MergedAnnotation.VALUE);}MergedAnnotation<?> priorityAnnotation = annotations.get(JAVAX_PRIORITY_ANNOTATION);if (priorityAnnotation.isPresent()) {// ### 重点!!!获取@Priority注解的value值return priorityAnnotation.getInt(MergedAnnotation.VALUE);}return null;
}
整理完毕,完结撒花~ 🌻
参考地址:
1.浅谈Spring @Order注解的使用,https://blog.csdn.net/yaomingyang/article/details/86649072
2.深入理解Spring的@Order注解和Ordered接口,https://blog.csdn.net/zkc7441976/article/details/112548075
3.踩坑!@Order失效。。。https://blog.csdn.net/qq_34142184/article/details/126951618
相关文章:

Spring(18) @Order注解介绍、使用、底层原理
目录 一、简介二、List 注入使用示例2.1 测试接口类2.2 测试接口实现类12.3 测试接口实现类22.4 启动类(测试)2.5 测试结果场景一:场景二: 三、CommandLineRunner 使用示例3.1 接口实现类13.2 接口实现类23.3 测试结果场景一&…...
目标检测YOLO实战应用案例100讲-基于改进YOLOv6的轧钢表面细小缺陷检测
目录 前言 存在的问题 轧钢缺陷图像特征分析 2.1单一类型缺陷 2.2面状缺陷...

leetcode:507. 完美数(python3解法)
难度:简单 对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」。 给定一个 整数 n, 如果是完美数,返回 true;否则返回 false。 示例 1: 输入:num…...

智能物联网解决方案:蓝牙IOT主控模块打造高效监测和超低功耗
物联网蓝牙模块,无论单模,还是双模,或者双模音频的选择,如下文说描述: 蓝牙芯片模块市场的百花齐放,也带来的工程师在选型时碰到很大的困难,但是无论是做半成品,还是做成品…...

vue 拿到数据后,没有重新渲染视图,nuxt.js拿到数据后,没有重新渲染视图,强制更新视图
以下为Vue2的解决方案 一、 Vue.set() 问:什么情况下使用? 答:如果你向响应式数据添加新的“属性”,理论上,一般情况下是没问题的,但是,如果你的级别比较深,又…...

Docker基础操作命令演示
Docker中的常见命令,可以参考官方文档:https://docs.docker.com/engine/reference/commandline/cli/ 1、常见命令介绍 其中,比较常见的命令有: 命令说明文档地址docker pull拉取镜像docker pulldocker push推送镜像到DockerReg…...
XTU-OJ 1175-Change
题目描述 一个班有N个学生,每个学生有第一学期成绩Xi,第二学期成绩Yi,请问成绩上升,持平,下降的人数。 输入 每个样例的第一行是整数N(0≤N≤50),如果N0,表示输入结束,这个样例不需要处理。 第二行是N个整数…...

Python环境安装
环境安装 Windows安装Linux安装 Windows安装 下载最新版Python https://www.python.org/downloads 打开安装包 选择安装路径,安装 安装 验证安装是否成功,命令行输入python Linux安装 安装依赖环境 yum install wget zlib-devel bzip2-devel op…...
苏轼在密州的四首千古名作
苏轼,一个从诗歌王国掉落人间的落魄贵族,整个政治生涯几乎都以流浪为主,在古诗词世界或许只有李白与之最是相似,不过李白的流浪属于荡歌山水、云游四方,而苏轼的流浪则带有被动的成分:一纸贬黜公文就是苏轼…...
[计算机提升] 域及域用户(组)
1.3 域及域用户(组) 1.3.1 域的概念 在Windows操作系统中,域(Domain)是指一个或多个计算机或资源的集合,这些计算机或资源受到单个安全数据库(域控制器)的管理和控制。域可以包含多个计算机、用户、组和其…...

命令行配置文件
在说具体的配置方式之前,我们需要首先梳理清除几个概念。这有助于我们明白自己在做什么,以及如何把经验平移到其他方面。 和命令行相关的有几个概念:terminal(终端)、shell(解释器);…...

MPP产品介绍-定位-应用场景-技术特点
产品定位 FusionInsight LibrA是企业级的大规模并行处理关系型数据库。FusionInsight LibrA采用MPP(Massive Parallel Processing)架构,支持行存储与列存储,提供PB(Petabyte,2的50次方字节)级别数据量的处理能力。 FusionInsight LibrA在核…...

Linux性能优化--性能工具:磁盘I/O
6.0 概述 本章介绍的性能工具能帮助你评估磁盘I/O子系统的使用情况。这些工具可以展示哪些磁盘或分区已被使用,每个磁盘处理了多少I/O,发给这些磁盘的I/O请求要等多久才被处理。 阅读本章后,你将能够: 确定系统内磁盘I/O的总量和类型(读/写…...

Archive Team: The Twitter Stream Grab
该集合不再更新,应被视为静态数据集。 从一般 Twitter 流中抓取的 JSON 的简单集合,用于研究、历史、测试和记忆的目的。这是“Spritzer”版本,最轻、最浅的 Twitter 抓取。不幸的是,我们目前无法访问流的洒水器或花园软管版本。 …...

Vue-props配置功能
Vue-props配置功能 props概述 功能:接收从其他组件传过来的数据,将数据从静态转为动态注意: 同一层组件不能使用props,必须是父组件传子组件的形式。父组件传数据,子组件接收数据。不能什么数据都接收,可…...

iMazing 3中文版功能介绍免费下载安装教程
iMazing 3中文版免费下载是一款兼容Win和Mac的iOS设备管理软件。iMazing 3能够将音乐、文件、消息和应用等数据从任何 iPhone、iPad 或 iPod 传输到 Mac 或 PC 上。 使用iMazing 3独特的 iOS 备份功能保证数据安全:设定自动无线备份时间并支持快照;将备份保存到外接驱动器和网…...

给课题组师弟师妹的开荒手册(终篇)
0 写在前面 终于,在结束收尾工作后敲下了开荒手册的终篇,自己三年研究生生活过的离理想中的完美还差很多,不过胜在完整,哈哈,小满胜万全嘛。希望以自己不太完美的经历为例,抛我的砖,引师弟师妹…...

【Eclipse】安装与卸载教程
目录 1.绿色版免安装版本 2.安装版本 3.卸载 首先打开官网:Eclipse Downloads | The Eclipse Foundation 选择download package 如图所示,到如下界面 1.绿色版免安装版本 按图片点击,即可开始下载 下载好后解压 ,在桌面创建…...
WordPress还是Shopify?如何选择最适合您业务的网站建设平台?
在当今数字化世界中,创建一个强大的在线存在对于任何业务来说都至关重要。然而,对于不熟悉编码或网站建设的人来说,选择合适的网站建设平台可能是一项挑战。在这个领域,两个主要的选项备受关注:WordPress和Shopify。让…...

Java Kids-百倍提速【Mac IOS】
引言:当今社会,创新和提升效率已经成为了大家普遍的追求。无论是个人生活还是企业经营,我们都希望能够以更高的效率完成任务,节省时间和资源。因此,提速成为了一种时代的要求,而"Java Kids 百倍提速&q…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
第22节 Node.js JXcore 打包
Node.js是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore是一个支持多线程的 Node.js 发行版本,基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 本文主要介绍JXcore的打包功能。 JXcore 安装 下载JXcore安装包&a…...