0


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

目录

一、简介

@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
 */publicinterfaceIOrderTest{/**
     * 处理
     */voidhandle();}

2.2 测试接口实现类1

@Order注解测试实现类01 和 @Order注解测试实现类02 实现了 IOrderTest 接口,用于测试 @Order 的生效。

OrderTestImpl01.java

importcom.demo.test.IOrderTest;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;/**
 * <p> @Title OrderTestA
 * <p> @Description @Order注解测试实现类01
 *
 * @author ACGkaka
 * @date 2023/10/17 11:18
 */@Order(1)@ComponentpublicclassOrderTestImpl01implementsIOrderTest{publicOrderTestImpl01(){System.out.println("=== OrderTestImpl01 constructor() ==");}@Overridepublicvoidhandle(){System.out.println("=== OrderTestImpl01 handle() ===");}}

2.3 测试接口实现类2

@Order注解测试实现类01 和 @Order注解测试实现类02 实现了 IOrderTest 接口,用于测试 @Order 的生效。

OrderTestImpl02.java

importcom.demo.test.IOrderTest;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;/**
 * <p> @Title OrderTestImpl02
 * <p> @Description @Order注解测试实现类02
 *
 * @author ACGkaka
 * @date 2023/10/17 11:18
 */@Order(2)@ComponentpublicclassOrderTestImpl02implementsIOrderTest{publicOrderTestImpl02(){System.out.println("=== OrderTestImpl02 constructor() ===");}@Overridepublicvoidhandle(){System.out.println("=== OrderTestImpl02 handle() ===");}}

2.4 启动类(测试)

SpringbootDemoApplication.java

importcom.demo.test.IOrderTest;importorg.springframework.boot.CommandLineRunner;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.annotation.Bean;importjava.util.List;@SpringBootApplicationpublicclassSpringbootDemoApplication{publicstaticvoidmain(String[] args){SpringApplication.run(SpringbootDemoApplication.class, args);}@BeanpublicCommandLineRunnercommandLineRunner(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

importorg.springframework.boot.CommandLineRunner;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;/**
 * <p> @Title CommandLineRunner01
 * <p> @Description @Order注解测试01
 *
 * @author ACGkaka
 * @date 2023/10/17 11:20
 */@Component@Order(1)publicclassCommandLineRunner01implementsCommandLineRunner{@Overridepublicvoidrun(String... args){System.out.println("=== CommandLineRunner01 ===");}}

3.2 接口实现类2

CommandLineRunner02.java

importorg.springframework.boot.CommandLineRunner;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;/**
 * <p> @Title CommandLineRunner02
 * <p> @Description @Order注解测试02
 *
 * @author ACGkaka
 * @date 2023/10/17 11:20
 */@Component@Order(2)publicclassCommandLineRunner02implementsCommandLineRunner{@Overridepublicvoidrun(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

importorg.springframework.boot.CommandLineRunner;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.annotation.Bean;importorg.springframework.core.annotation.Order;@SpringBootApplicationpublicclassSpringbootDemoApplication{publicstaticvoidmain(String[] args){SpringApplication.run(SpringbootDemoApplication.class, args);}@Order(2)@BeanpublicCommandLineRunnercommandLineRunner01(){return args ->System.out.println("=== commandLineRunner01 ===");}@Order(1)@BeanpublicCommandLineRunnercommandLineRunner02(){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

@SpringBootApplicationpublicclassSpringbootDemoApplication{publicstaticvoidmain(String[] args){SpringApplication.run(SpringbootDemoApplication.class, args);}}

5.2 神奇的 run() 方法

SpringApplication.run()

publicConfigurableApplicationContextrun(String... args){StopWatch stopWatch =newStopWatch();
    stopWatch.start();ConfigurableApplicationContext context =null;Collection<SpringBootExceptionReporter> exceptionReporters =newArrayList<>();configureHeadlessProperty();SpringApplicationRunListeners listeners =getRunListeners(args);
    listeners.starting();try{ApplicationArguments applicationArguments =newDefaultApplicationArguments(args);ConfigurableEnvironment environment =prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner =printBanner(environment);
        context =createApplicationContext();
        exceptionReporters =getSpringFactoriesInstances(SpringBootExceptionReporter.class,newClass[]{ConfigurableApplicationContext.class}, context);prepareContext(context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);
        stopWatch.stop();if(this.logStartupInfo){newStartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}
        listeners.started(context);// #### 重点!!!调用具体的执行方法 ###callRunners(context, applicationArguments);}catch(Throwable ex){handleRunFailure(context, ex, exceptionReporters, listeners);thrownewIllegalStateException(ex);}try{
        listeners.running(context);}catch(Throwable ex){handleRunFailure(context, ex, exceptionReporters,null);thrownewIllegalStateException(ex);}return context;}

5.3 开始排序的 callRunners() 方法

SpringApplication.callRunners()

privatevoidcallRunners(ApplicationContext context,ApplicationArguments args){List<Object> runners =newArrayList<>();
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());// ### 重点!!!按照定义的优先级顺序排序 ###AnnotationAwareOrderComparator.sort(runners);for(Object runner :newLinkedHashSet<>(runners)){if(runner instanceofApplicationRunner){callRunner((ApplicationRunner) runner, args);}if(runner instanceofCommandLineRunner){callRunner((CommandLineRunner) runner, args);}}}

5.4 排序调用图

由于剩下的实现内容调用链比较长,为了看起来更清晰直观,采用顺序图展现出来:

#mermaid-svg-091ep2ylgaclhhBs {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-091ep2ylgaclhhBs .error-icon{fill:#552222;}#mermaid-svg-091ep2ylgaclhhBs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-091ep2ylgaclhhBs .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-091ep2ylgaclhhBs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-091ep2ylgaclhhBs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-091ep2ylgaclhhBs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-091ep2ylgaclhhBs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-091ep2ylgaclhhBs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-091ep2ylgaclhhBs .marker.cross{stroke:#333333;}#mermaid-svg-091ep2ylgaclhhBs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-091ep2ylgaclhhBs .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-091ep2ylgaclhhBs text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-091ep2ylgaclhhBs .actor-line{stroke:grey;}#mermaid-svg-091ep2ylgaclhhBs .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-091ep2ylgaclhhBs .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-091ep2ylgaclhhBs #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-091ep2ylgaclhhBs .sequenceNumber{fill:white;}#mermaid-svg-091ep2ylgaclhhBs #sequencenumber{fill:#333;}#mermaid-svg-091ep2ylgaclhhBs #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-091ep2ylgaclhhBs .messageText{fill:#333;stroke:#333;}#mermaid-svg-091ep2ylgaclhhBs .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-091ep2ylgaclhhBs .labelText,#mermaid-svg-091ep2ylgaclhhBs .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-091ep2ylgaclhhBs .loopText,#mermaid-svg-091ep2ylgaclhhBs .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-091ep2ylgaclhhBs .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-091ep2ylgaclhhBs .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-091ep2ylgaclhhBs .noteText,#mermaid-svg-091ep2ylgaclhhBs .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-091ep2ylgaclhhBs .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-091ep2ylgaclhhBs .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-091ep2ylgaclhhBs .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-091ep2ylgaclhhBs .actorPopupMenu{position:absolute;}#mermaid-svg-091ep2ylgaclhhBs .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-091ep2ylgaclhhBs .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-091ep2ylgaclhhBs .actor-man circle,#mermaid-svg-091ep2ylgaclhhBs line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-091ep2ylgaclhhBs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
SpringApplication

   AnnotationAwareOrderComparator 
 
   List 
 
   OrderComparator 
 
   OrderUtils 
 
run() 

callRunners() 

sort() 

sort() 

compare() 

doCompare() 

getOrder() 

findOrder() 

findOrderFromAnnotation() 

getOrderFromAnnotations() 

findOrder() 

  SpringApplication 

  AnnotationAwareOrderComparator 

  List 

  OrderComparator 

  OrderUtils 

5.5 排序的根源 findOrder() 方法

获取 @Order 注解的 value 值,来进行排序。

OrderUtils.findOrder()

@NullableprivatestaticIntegerfindOrder(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);}returnnull;}

整理完毕,完结撒花~ 🌻

参考地址:

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 java 后端

本文转载自: https://blog.csdn.net/qq_33204709/article/details/133888330
版权归原作者 ACGkaka_ 所有, 如有侵权,请联系我们删除。

“Spring(18) @Order注解介绍、使用、底层原理”的评论:

还没有评论