Spring源码必备-@Order排序详解

SSM-Project-Day07 AOP【切面排序@Order(1)数字越小优先级越高】 一、添加pom依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.9.RELEASE</version> ... 阅读详情

大家都知道Spring中可以使用@Order和@Priority来决定SpringBean的启动顺序,但是你知道他是怎么实现的吗?

下面我们就来看看Spring是怎么设计实现的。

一、如何使用

我们先看看Spring是如何使用的,然后再深入内部去看。

public class SpringApplication {
	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        //排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
}

//进行排序的类
public class AnnotationAwareOrderComparator extends OrderComparator {
	public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
	public static void sort(List<?> list) {
		if (list.size() > 1) {
			list.sort(INSTANCE);
		}
	}
}

以上代码是SpringBoot启动刚开始的时候的一段代码,我加了注释的那行就是进行排序的。

该类的结构关系如下:

 Spring中排序使用的就是AnnotationAwareOrderComparator类,可以看出上层接口是Comparator,java的比较器我们都很熟悉了,这里就不多说了。

我们自己再写个小例子看看:

public class Test {
    public static void main(String[] args){
        List<A> list = new ArrayList<>();
        list.add(new A2());
        list.add(new A3());
        list.add(new A1());
        AnnotationAwareOrderComparator.sort(list);
        for (A a : list){
            a.say();
        }
    }
}

interface A{
    void say();
}
@Order(1)
class A1 implements A{
    public void say(){
        System.out.println(1);
    }
}
@Order(2)
class A2 implements A{
    public void say(){
        System.out.println(2);
    }
}
@Priority(3)
class A3 implements A{
    public void say(){
        System.out.println(3);
    }
}

以上代码写的是按不同顺序放入list,排序后,按照@Order和@Priority标注的顺序就行了排序。 

二、相关抽象类解释

Java是面向对象的语言,我们千万不能忘记这一点。我们可以把任何概念或者事物抽象成一个对象,Spring也不例外,所以,我们了解他的某一块功能,要先去了解Spring为了实现这个功能抽象出了哪些类。

2.1 @Order和@Priority

@Target({TYPE,PARAMETER})
@Retention(RUNTIME)
@Documented
public @interface Priority {
    int value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {
	int value() default Ordered.LOWEST_PRECEDENCE;

}

这两个注解的区别就是,@Order有一个默认值,他两的标注范围也不同。

从之前的自己写的小例子也可以看出,这两个注解是被排序功能识别的,并不需要相关对象注入到Spring容器中。

2.2  查找策略SearchStrategy

Spring排序是实现了java的比较器Comparator,所以必须获取注解上表示大小的值。有查找就有了策略,是只查找当前类还是需要查找父类。

	enum SearchStrategy {
		/**
		 * 只查找当前类,不考虑@Inherited、父类和实现的接口
		 */
		DIRECT,
		/**
		 * 查找当前类和@Inherited,不查找父类和实现的接口
		 */
		INHERITED_ANNOTATIONS,
		/**
		 * 查找当前类和父类,不查找实现的接口
		 */
		SUPERCLASS,
		/**
		 * 查找当前类、父类、实现的接口
		 */
		TYPE_HIERARCHY,
		/**
		 * 在TYPE_HIERARCHY基础上还查找外部类(如果当前类是内部类)
		 */
		TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
	}

 小知识:@Inherited 子类会继承父类的注解。实现类不会继承接口的注解、子接口不会继承父接口的注解

2.3 RepeatableContainers

 小知识:

@Repeatable:正常情况下同一个注解只能标注一次,而@Repeatable可以实现标注多次

如果出现下面这种情况,就得使用该类来解决了:

@Repeatable(persons.class)
@Order
@interface person{
    String value();
}

@interface persons{
    person[] value();
}

@persons({@person("a"), @person("b")})
class A{
}
@person("a")
@person("b")
class B{
}

 如果有自定义注解比如@person,那么获取A类的Order值就很麻烦了。RepeatableContainers就是做这个事的。它负责最终找出@Order注解。

2.4 注解过滤器AnnotationFilter

 这个类很简单,只有一个实现类,该类用来排除不需要查找的注解。

@FunctionalInterface
public interface AnnotationFilter {
	AnnotationFilter PLAIN = packages("java.lang", "org.springframework.lang");
	static AnnotationFilter packages(String... packages) {
		return new PackagesAnnotationFilter(packages);
	}
}

final class PackagesAnnotationFilter implements AnnotationFilter {
	@Override
	public boolean matches(String annotationType) {
		for (String prefix : this.prefixes) {
			if (annotationType.startsWith(prefix)) {
				return true;
			}
		}
		return false;
	}
}

如上代码,Spring中排除了java.lang和org.springframework.lang下的注解。

三、整个过程

整个排序过程,最重要也是最不容易阅读的代码就是查找Order值的过程,入口方法如下:

public class OrderComparator implements Comparator<Object> {
	@Nullable
	protected Integer findOrder(Object obj) {
		return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null);
	}
}

public class AnnotationAwareOrderComparator extends OrderComparator {	
    @Override
	@Nullable
	protected Integer findOrder(Object obj) {
		Integer order = super.findOrder(obj);
		if (order != null) {
			return order;
		}
		return findOrderFromAnnotation(obj);
	}

	@Nullable
	private Integer findOrderFromAnnotation(Object obj) {
		AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass());
		MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
		Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
		if (order == null && obj instanceof DecoratingProxy) {
			return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
		}
		return order;
	}
}

首先调用父类方法,是否是Ordered接口的实现类,如果是,则直接调用方法获取值,如果不是则调用子方法。

子方法第一步首先获取Class对象。

AnnotatedElement是Class的父类。

第二步,查找前的准备工作。

第三步,从所有注解中过滤出order值。

第四部,如果找到直接返回,找不到并且是代理类的话,用目标对象再次走一遍刚才的流程。

代码中最重要的有2个

  • 查找前的准备工作。
  • OrderUtils类负责从注解中查找出order值。

3.1 准备工作

从静态方法from进入,我们可以看到初始化了以下内容:

  1. 策略选择的是TYPE_HIERARCHY
  2. 容器选择的是StandardRepeatableContainers
  3. Filter选择排除的是"java.lang", "org.springframework.lang"

3.2 过滤

这部分的代码量最大,这里不详细展开,大家可以自己简单看看,看的方法还是和之前一样,按功能模块看,不要从头到尾一直往下读。

	@Nullable
	private static Integer findOrder(MergedAnnotations annotations) {
		MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
		if (orderAnnotation.isPresent()) {
			return orderAnnotation.getInt(MergedAnnotation.VALUE);
		}
		MergedAnnotation<?> priorityAnnotation = annotations.get(JAVAX_PRIORITY_ANNOTATION);
		if (priorityAnnotation.isPresent()) {
			return priorityAnnotation.getInt(MergedAnnotation.VALUE);
		}
		return null;
	}

以上为外层方法,看着很容易,调用MergedAnnotations的get方法先查找Order注解的值,有就返回,没有则查找javax.annotation.Priority注解的值。

四、总结

如果大家一边翻看源码,一边看本文,应该对Spring如何实现Order很了解了。

一个简单的Order,涉及到的代码和抽象概念都很多,包括了过滤、策略、Repeatable容器查找等,如果你详细看的话还会发现别的抽象接口,比如Finder什么的,不过那是更细节的代码了。


欢迎讨论交流

Spring框架中的@Order注解详解及应用实例 Order注解位于包中,它可以用来指定Bean的加载顺序。如果没有指定@Order,Spring默认的顺序是。 阅读详情

相关推荐

Spring框架中的@Order注解详解与实例

Order默认情况下,如果没有指定value属性,其值将为,表示Bean将被加载在最后。通过本文,我们了解了@Order注解在Spring框架中的重要性以及如何使用它来控制Bean的加载顺序。希望这些示例能帮助你在实际开发中更好地利用这一特性。

m0_62153576的博客 622

@order 注解用法

@order注解是spring-core包下的一个注解,@Order的作用是定义Spring IOC容器中Bean的执行顺序的优先级(这里的顺序也可以理解为存放到容器中的先后顺序)。开发过程当中有时候经常会出现配置依赖关系,例如注入A对象使用了@ConditionalOnBean(B.class),意思是要求容器当中必须存在B.class的实例的时候,才会进行注入A。这时候我们就必须保证B对象在注入A对象前进行注入。

怪咖@的博客 4万+

AXI Timer IP核使用说明

AXI Timer是提供定时技术功能的集成IP核,具有时间生成、事件捕获、产生PWM波以及产生中断的功能,下面具体讲述Timer IP核的使用说明。

weixin_43418104的博客 2484

Spring(18) @Order注解介绍、使用、底层原理

Spring(18) @Order注解介绍、使用、底层原理

ACGkaka的博客 9821

ESP32—C3实现网页跳转

用户点击HTML页面中的按钮。浏览器根据按钮的href属性向服务器发送HTTP GET请求。服务器根据请求的URL调用相应的回调函数。服务器发送包含新页面HTML内容的HTTP响应。浏览器解析并显示新的HTML页面。这个过程对于用户来说是无缝的,看起来就像是直接从一个页面跳转到另一个页面。实际上,背后发生了HTTP请求和响应的过程。

qq_59527512的博客 1022

基于mediapipe的动作捕捉和unity的人物模型驱动

用到的人体关键点检测的算法是Google开发的基于深度学习的实时多媒体套件,汇集了人体、手部、人脸关键点追踪、物体检测、物体识别等多个流行的视觉任务的成果。整套 Mediapipe正如其名字,专门为便携设备上的多媒体应用设计,模型非常小,在笔记本手机上也能实时跑,跨平台、跨语言。mediapipe实时性是没什么问题。但是是以牺牲了质量为代价的,这种关键点检测一般是用来做动作识别,类似于运动app跳绳计数、判定瑜伽动作标不标准这种。用单目视觉来做人物模型的驱动,总差点意思。

qq_58484580的博客 5726

深入解析Spring Boot中的Bean加载顺序控制

在Spring Boot应用的启动过程中,Bean的加载顺序往往决定了系统初始化的成败。当容器需要初始化数百个相互依赖的Bean时,错误的加载顺序可能导致依赖注入失败、循环依赖甚至应用启动崩溃。特别是在2025年的现代微服务架构中,随着自动配置机制的广泛应用,理解并控制Bean加载顺序已成为高级开发者的必备技能。启动日志分析。

zuiyuelong的博客 1323

基于KiCad的STM32最小系统设计实战案例(含PCB布线)

手把手带你用KiCad完成STM32最小系统设计,涵盖原理图绘制、封装匹配、规则约束设置及关键信号PCB布线技巧;全程基于开源EDA工具KiCad,强调实操细节与常见坑点规避。

weixin_42452483的博客 355

Feign拦截器RequestInterceptor优先级实战指南

本文深入解析了Feign拦截器中RequestInterceptor的优先级排序机制。通过剖析其核心工作原理,详细介绍了PriorityOrdered接口、Ordered接口和@Order注解三大控制手段,并结合实战场景(如链路追踪、安全认证、请求签名)提供了多拦截器的编排策略与调试方法,帮助开发者避免因执行顺序混乱导致的常见生产问题。

sam99的博客 419

计算机视觉与深度学习实战:以Python为工具,基于帧间差法进行视频目标检测

计算机视觉是一门研究如何使机器从数字图像或视频中提取、分析和理解有用信息的学科。它涉及图像处理、计算机图形学、人工智能等多个领域的知识。通过计算机视觉技术,我们可以实现图像的识别、分类、目标检测等功能。本文介绍了计算机视觉与深度学习的基本概念和原理,并以Python为工具,基于帧间差分法实现了视频目标检测。帧间差分法具有算法实现简单、程序设计复杂度低、对光线等场景变化不太敏感等优点,因此在实际应用中得到了广泛的应用。然而,帧间差分法也存在一些局限性,如对于缓慢移动或静止的物体检测效果不佳。

一个好知识的传播者 1255

深入解析STM32官方库:.c/.h文件功能与应用场景

本文深入解析了STM32官方库中.c和.h文件的核心功能与应用场景。详细剖析了stm32f10x.h、启动文件、外设驱动文件等关键组件的作用,并通过LED闪烁实战演示了如何构建工程、配置文件和调用库函数。文章旨在帮助开发者理解官方库的架构,掌握高效使用技巧,从而降低STM32开发门槛,提升开发效率与代码质量。

weixin_29189377的博客 346

深入分析Spring的@Order注解

一文让你理解Spring中的@Order注解的作用。

L的博客 4851

AES加密算法及AES-CMAC原理白话版系统解析

对AES不同加密算法,加密模式,加密原理,填充算法及AES-CMAC算法的详细系统介绍,帮助大家对AES进行系统掌握。

initiallizer的博客 4066

Java注解篇:@Order

@Order注解在Spring框架中用于定义组件的排序优先级,值越小优先级越高。它不控制Bean的加载或实例化顺序,而是影响执行或注入时的顺序。

x² 2737

化工设计软件:PDMS二次开发_(7).数据导入与导出技术

在某些复杂场景下,PDMS提供的标准API接口可能无法满足需求。此时,可以通过自定义API接口来实现特定的数据导入与导出功能。自定义设备导入API接口可以处理更复杂的设备数据格式。# 导入必要的库import pdms_api # 假设有一个PDMS API库# 定义自定义设备数据# 自定义设备导入API接口# 调用自定义设备导入API接口# 输出导入成功的消息print("自定义设备数据导入成功")在PDMS二次开发中,数据的导入与导出是关键的技术环节。

kkchenjj的博客 1484

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【java知识点】常用注解解析

【java知识点】常用注解解析

等待中的小码农 3142

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Spring注解--@Order--使用/实例

本文用示例介绍@Order(顺序)注解的用法。

IT利刃出鞘的博客 4995

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

springboot注解@Order的使用

使用order属性,设置该类在spring容器中的加载顺序 例如有三个类:Order1,Order2,Order3,其中Order1类如下: @Component //把类交给spring容器管理 @Order(1) //使用order属性,设置该类在spring容器中的加载顺序 public class Order1{ private final int ORDERED = 1; ...

zhizhuodewo6的博客 2万+

浅谈Spring @Order注解的使用

注解@Order的作用是定义Spring容器加载Bean的顺序,接下来我们通过分析源码和示例测试详细的学习。 1.@Order的注解源码解读 注解类: @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Documented public @i...

OceanSky的专栏 20万+

注解详解系列 - @Order:控制Bean加载顺序

在今天的注解详解系列中,我们将探讨@Order注解。@Order是Spring框架中的一个重要注解,用于控制Spring容器中Bean的加载顺序。通过@Order注解,可以指定多个Bean的优先级,从而决定它们的执行或加载顺序。@Order注解用于定义Spring容器中Bean的加载顺序。它可以应用于类级别或方法级别,通常与实现了Ordered接口的类一起使用。

算命de博客 1759

Spring | @Order 与 Ordered 控制加载顺序

阐述了 @Order 与 Ordered 的区别, 使用方式, 以及@Order源码 是在哪里进行控制顺序的

苏老师的博客 4049

Spring Boot 中优雅地使用责任链模式(@Order 实战)

摘要:当业务逻辑中的if-else判断过多时,责任链模式是最佳解决方案。本文介绍了如何利用Spring Boot的@Order注解实现责任链模式,将复杂的业务流程分解为多个独立处理单元。通过定义Handler接口、Context对象和Chain执行器,配合@Order控制执行顺序,可以有效消除冗长的if-else结构,使代码更清晰、可维护性更强。这种模式特别适合导出流程、审批流等场景,让复杂业务逻辑像流水线一样清晰可控。

Knight 1227

@Order注解使用

注解@Order或者接口Ordered的作用是定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序,Bean的加载顺序不受@Order或Ordered接口的影响 1.@Order的注解源码解读 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Documented public @interface Order {

吾心即悟的博客 2356

Spring 框架中 @Order 注解:使用教程、原理剖析与应用场景

它通过定义优先级来影响Bean在集合中的注入顺序、切面的执行顺序以及特定扩展点(如过滤器、监听器)的排序。它通过定义优先级来影响Bean在集合中的注入顺序、切面的执行顺序以及特定扩展点(如过滤器、监听器)的排序。,可以确保Spring应用的组件按预期协同工作,提升系统的可维护性和稳定性。,可以确保Spring应用的组件按预期协同工作,提升系统的可维护性和稳定性。是Spring框架中实现组件排序的核心工具,其核心价值在于。是Spring框架中实现组件排序的核心工具,其核心价值在于。等注解解决复杂的顺序问题。

qq_35800459的博客 1785

@Order 注解

@Order 注解 @Order注解主要用来控制配置类的加载顺序 示例代码: package com.runlion.tms.admin.constant; public class AService { } package com.runlion.tms.admin.constant; public class BService { } package com.runlion....

优质后端技术知识记录 1万+

spring boot @Order 注解的使用场景

在中,@Order注解用于定义或的优先级顺序。它可以应用于过滤器、切面(Aspect)、监听器或其他需要顺序执行的组件。@Order注解来源于,其值为整数,表示顺序的优先级,值越小优先级越高(即最小的值会最先执行)。@Order。

学亮编程手记 1543
上一篇: 读Spring源码必备-资源访问
下一篇: Spring源码阅读之PropertySource
七号公园的忧伤
七号公园的忧伤 新星创作者: Java技术领域 新星创作者: Java技术领域
博客等级 码龄6年 4857粉丝 79原创
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七号公园的忧伤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值