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…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...
TJCTF 2025
还以为是天津的。这个比较容易,虽然绕了点弯,可还是把CP AK了,不过我会的别人也会,还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
