@Order:是 spring-core 包下的一个注解。@Order 作用是定义 Spring IOC 容器中 Bean 的执行顺序。
注意: Spring 的 @Order 注解或者 Ordered 接口,不决定 Bean 的加载顺序和实例化顺序,只决定 Bean 注入到 List 中的顺序。
@Order 注解接受一个整数值作为参数,数值越小表示优先级越高。当存在多个具有 @Order 注解的组件时,Spring Boot将按照数值从小到大的顺序加载它们。
需要注意的是:
包结构如下:
IOrderTest 接口中定义了一个 handle() 方法用于测试。
IOrderTest.java
/** *@Title IOrderTest *
@Description @Order注解测试接口 * * @author ACGkaka * @date 2023/10/17 11:20 */ public interface IOrderTest { /** * 处理 */ void handle(); }
@Order注解测试实现类01 和 @Order注解测试实现类02 实现了 IOrderTest 接口,用于测试 @Order 的生效。
OrderTestImpl01.java
import com.demo.test.IOrderTest; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** *@Title OrderTestA *
@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() =="); } @Override public void handle() { System.out.println("=== OrderTestImpl01 handle() ==="); } }
@Order注解测试实现类01 和 @Order注解测试实现类02 实现了 IOrderTest 接口,用于测试 @Order 的生效。
OrderTestImpl02.java
import com.demo.test.IOrderTest; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** *@Title OrderTestImpl02 *
@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() ==="); } @Override public void handle() { System.out.println("=== OrderTestImpl02 handle() ==="); } }
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); } @Bean public CommandLineRunner commandLineRunner(Listlist) { return args -> { System.out.println("=== CommandLineRunner ==="); list.forEach(IOrderTest::handle); }; } }
执行结果如下:
执行结果如下:
CommandLineRunner01.java
import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** *@Title CommandLineRunner01 *
@Description @Order注解测试01 * * @author ACGkaka * @date 2023/10/17 11:20 */ @Component @Order(1) public class CommandLineRunner01 implements CommandLineRunner { @Override public void run(String... args) { System.out.println("=== CommandLineRunner01 ==="); } }
CommandLineRunner02.java
import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** *@Title CommandLineRunner02 *
@Description @Order注解测试02 * * @author ACGkaka * @date 2023/10/17 11:20 */ @Component @Order(2) public class CommandLineRunner02 implements CommandLineRunner { @Override public void run(String... args) { System.out.println("=== CommandLineRunner02 ==="); } }
执行结果如下:
执行结果如下:
失效场景: 在 @Configuration 里面通过 @Bean 方式创建 Bean,在上面加 @Order 控制顺序是没有效果的。
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) @Bean public CommandLineRunner commandLineRunner01() { return args -> System.out.println("=== commandLineRunner01 ==="); } @Order(1) @Bean public CommandLineRunner commandLineRunner02() { return args -> System.out.println("=== commandLineRunner02 ==="); } }
由下图可知,虽然我们使用 @Order 注解明确声明要先执行 commandLineRunner02,但是并没有生效。
在 @Order 注解失效的场景下,可以通过以下方式来控制顺序:
看完 @Order 注解的时候,可能会疑惑 IOC 容器时如何通过 @Order 注解来控制程序的先后顺序的,接下来我们从源码层面看下,容器是如何加载的。
先说结论:
SpringbootDemoApplication.java
@SpringBootApplication public class SpringbootDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootDemoApplication.class, args); } }
SpringApplication.run()
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; CollectionexceptionReporters = 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; }
SpringApplication.callRunners()
private void callRunners(ApplicationContext context, ApplicationArguments args) { List
由于剩下的实现内容调用链比较长,为了看起来更清晰直观,采用顺序图展现出来:
获取 @Order 注解的 value 值,来进行排序。
OrderUtils.findOrder()
@Nullable private static Integer findOrder(MergedAnnotations annotations) { MergedAnnotationorderAnnotation = 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