@Order
注解定义了类、方法和字段的优先级(排序情况),value
是可选的,默认为Ordered.LOWEST_PRECEDENCE,即最低优先级。表示 Ordered
接口中的 order 属性。
目前看到的 @Order 注解都是用在类上的,没有看到过用在方法和字段上的,包括 Spring 自有类 DefaultErrorAttributes、LogbackLoggingSystem.Factory 等。
1 2 3 4 5 6 7 8 9 10 11 12 13 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Documented public @interface Order { int value () default Ordered.LOWEST_PRECEDENCE; }
从 Spring 4.0 开始,Spring 中的很多组件都支持基于 Order
注解的排序,但是使用了该注解后,不会影响bean的加载顺序,Bean的加载顺序是由依赖关系和 @DependsOn 注解来决定的。
我们定义两个bean:OrderBean1和OrderBean2,然后通过 @Bean 注入到容器中,启动 SpringBoot 应用,看看打印情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class OrderBean1 { public OrderBean1 () { System.out.println("init Order Bean 1" ); } } public class OrderBean2 { public OrderBean2 () { System.out.println("init Order Bean 2" ); } } @Configuration @Order(200) public class BeanConfig { public BeanConfig () { System.out.println("bean config" ); } @Bean public OrderBean1 orderBean1 () { return new OrderBean1 (); } } @Configuration @Order(100) public class BeanConfig2 { public BeanConfig2 () { System.out.println("bean config 2" ); } @Bean public OrderBean2 orderBean2 () { return new OrderBean2 (); } }
虽然 BeanConfig 和 BeanConfig2 都加了 Order 注解,且 BeanConfig2 的优先级更高,但是实际的日志打印是
1 2 3 4 bean config bean config 2 init Order Bean 1 init Order Bean 2
BeanConfig2 并没有优先于 BeanConfig 进行加载。
如果想要 BeanConfig2 优先加载,可以借助 @DependsOn 注解。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Configuration @DependsOn("beanConfig2") public class BeanConfig1 { public BeanConfig1 () { System.out.println("bean config 1" ); } @Bean @DependsOn("orderBean2") public OrderBean1 orderBean1 () { return new OrderBean1 (); } }
日志打印为:
1 2 3 4 bean config 2 bean config 1 init Order Bean 2 init Order Bean 1
那 Order 注解在什么场景下才能使用呢?在进行执行顺序的排序时使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public interface OrderBean { void order () ; } @Order(200) public class OrderBean1 implements OrderBean { @Override public void order () { System.out.println("order bean1 ---> order command" ); } } @Order(100) public class OrderBean2 implements OrderBean { @Override public void order () { System.out.println("order bean2 ---> order command" ); } } @Configuration public class BeanCommandConfig { public BeanCommandConfig (List<OrderBean> orderBeans) { orderBeans.forEach(orderBean -> orderBean.order()); } }
输出信息为
1 2 order bean2 ---> order command order bean1 ---> order command
可以看到,先删除了 bean2 的内容,再输出了 bean1 的内容。
SpringBoot中的典型应用就是 CommandLineRunner。
Interface used to indicate that a bean should run when it is contained within a SpringApplication. Multiple CommandLineRunner beans can be defined within the same application context and can be ordered using the Ordered interface or @Order annotation.
翻译:多个CommandLineRunner bean 可以在同一个应用程序上下文中定义,并且可以使用Ordered接口或@Order注释进行排序
示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Component @Order(5) public class Runner1 implements CommandLineRunner { @Override public void run (String... args) throws Exception { System.out.println("runner 1 start" ); } } @Component @Order(1) public class Runner2 implements CommandLineRunner { @Override public void run (String... args) throws Exception { System.out.println("runner 2 start" ); } }
启动 SpringBoot 工程,查看控制台输出
1 2 runner 2 start runner 1 start
可以看到,两个 Runner 按照配置的优先级执行,先运行 Runner2,再运行 Runner1。
从 Spring 4.1 开始,jakarta.annotation.Priority
可在一些排序场景中替代 @Order
的作用,但是在修饰单个元素时,@Priority
可能具有其他语义。
除了这两个注解外,也可以实现 Ordered
接口,来设置优先级信息,相对使用注解的方式更加灵活。