@Order 注解定义了类、方法和字段的优先级(排序情况),value 是可选的,默认为Ordered.LOWEST_PRECEDENCE,即最低优先级。表示 Ordered 接口中的 order 属性。

目前看到的 @Order 注解都是用在类上的,没有看到过用在方法和字段上的,包括 Spring 自有类 DefaultErrorAttributes、LogbackLoggingSystem.Factory 等。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {
​
    /**
     * 优先级排序值,value 的值越大,优先级越低
     * 默认值为 Ordered.LOWEST_PRECEDENCE(Integer.MAX_VALUE) 
     * @see Ordered#getOrder()
     */
    int value() default Ordered.LOWEST_PRECEDENCE;
​
}

从 Spring 4.0 开始,Spring 中的很多组件都支持基于 Order 注解的排序,但是使用了该注解后,不会影响bean的加载顺序,Bean的加载顺序是由依赖关系和 @DependsOn 注解来决定的。

我们定义两个bean:OrderBean1和OrderBean2,然后通过 @Bean 注入到容器中,启动 SpringBoot 应用,看看打印情况。

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 的优先级更高,但是实际的日志打印是

bean config
bean config 2
init Order Bean 1
init Order Bean 2

BeanConfig2 并没有优先于 BeanConfig 进行加载。

如果想要 BeanConfig2 优先加载,可以借助 @DependsOn 注解。

@Configuration
@DependsOn("beanConfig2")
public class BeanConfig1 {
​
    public BeanConfig1() {
        System.out.println("bean config 1");
    }
​
    @Bean
    @DependsOn("orderBean2")
    public OrderBean1 orderBean1() {
        return new OrderBean1();
    }
}

日志打印为:

bean config 2
bean config 1
init Order Bean 2
init Order Bean 1

那 Order 注解在什么场景下才能使用呢?在进行执行顺序的排序时使用。

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

输出信息为

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注释进行排序

示例如下:

@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 工程,查看控制台输出

runner 2 start
runner 1 start

可以看到,两个 Runner 按照配置的优先级执行,先运行 Runner2,再运行 Runner1。

从 Spring 4.1 开始,jakarta.annotation.Priority 可在一些排序场景中替代 @Order 的作用。

除了这两个注解外,也可以实现 Ordered 接口,来设置优先级信息,相对使用注解的方式更加灵活。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐