在spring-boot 2.6.2下测试,@Order并不会影响bean的装载程序,申明了@Component的类,无论是构造方法、@PostConstruct注解申明的办法,还是实现的InitializingBean接口中的afterPropertiesSet()办法,如果beanClass位于同样的目录层级,这些办法的调用只会受到className的程序影响:

@Component@Slf4j@Order(2)public class Bean1 implements InitializingBean {    public Bean1() {        log.info("construct bean1");    }    @Override    public void afterPropertiesSet() throws Exception {        log.info("initialled bean1");    }    @PostConstruct    public void post() {        log.info("post bean1");    }}@Component@Slf4j@Order(1)public class Bean2 implements InitializingBean {    public Bean2() {        log.info("construct bean2");    }    @Override    public void afterPropertiesSet() throws Exception {        log.info("initialled bean2");    }    @PostConstruct    public void post() {        log.info("post bean2");    }}/* 后果打印程序:construct bean1post bean1initialled bean1construct bean2post bean2initialled bean2*/

察看@Order的注解阐明,第一句写着: @Order defines the sort order for an annotated component. 提到这个注解只是对component排序,那么哪里会收到这个排序数值的影响呢?

这里先革新一下代码:

public interface IBean {    void work();}@Component@Slf4j@Order(2)public class Bean1 implements InitializingBean,CommandLineRunner,IBean {    public Bean1() {        log.info("construct bean1");    }    @Override    public void afterPropertiesSet() throws Exception {        log.info("initialled bean1");    }    @PostConstruct    public void post() {        log.info("post bean1");    }    @Override    public void run(String... args) throws Exception {        log.info("running bean1");    }    @Override    public void work() {        log.info("bean1 is working");    }}@Component@Slf4j@Order(1)public class Bean2 implements InitializingBean, CommandLineRunner, IBean {    public Bean2() {        log.info("construct bean2");    }    @Override    public void afterPropertiesSet() throws Exception {        log.info("initialled bean2");    }    @PostConstruct    public void post() {        log.info("post bean2");    }    @Override    public void run(String... args) throws Exception {        log.info("running bean2");    }    @Override    public void work() {        log.info("bean2 is working");    }}@Service@RequiredArgsConstructorpublic class TestService {    private final List<IBean> beans;    public void test(){        beans.forEach(IBean::work);    }}

启动之后执行TestServicetest办法,失去如下程序的日志:

construct bean1post bean1initialled bean1construct bean2post bean2initialled bean2running bean2running bean1bean2 is workingbean1 is working

作一下阐明,@Order会影响依赖注入的程序,如果存在同样类型的多个bean,且依赖申明应用了List<BeanInterface>,会将所有bean实例依照Order申明的程序放入一个ArrayList中注入,如果用的是Collection或者Set则有效,因为类型自身无序。

而CommandLineRunner申明的run办法,会在bean被IOC容器拆卸实现之后被调用,办法正文简单明了的一句Callback used to run the bean能够了解为bean实例真正构建实现之后的回调办法,而这个办法会受到@Order的程序影响,成果后面日志中曾经体现,这里贴一下类正文:

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.

除了以上两种用法,@Aspect申明的切面类、继承了OncePerRequestFilter的过滤器等,它们的作用程序也会受到Order的影响。

留神:如果@Order注解配置在了@Configuration润饰的配置类中的@Bean办法润饰的办法上时,指定程序并不会失效

顺便提一下另外一个注解:@Priority,以上@Order能起作用的中央,换成@Priority一样会失效,但在一种状况下,它的作用和@Order大为不同:

同一个接口类型有多个不同的bean实现类时,注入依赖时应用汇合申明不会报错,但申明为单体类型时,如果各个Bean类应用了@Order申明,就会报required a single bean, but x were found的谬误,这时有两种办法能够解决问题,一是在其中一个Bean类加上@Primary的注解申明为首要类型,另外一个就是把Order改成Priority,优先级最高的那个bean会被当作primary来看待。

除了@Order注解,spring boot中还有一些用于调整配置加载程序的注解,比方 @AutoConfigureOrder@AutoConfigureBefore@AutoConfigureAfter等,这一类 @Auto 打头的注解,顾名思义,都是用在调整主动配置的解决程序上,也就是基于 spring-boot的META-INF/spring.factories管制的这些主动配置类。如果在你的我的项目中他们有明确的依存关系,能够用以上注解来解决。用起来也都比较简单直观。

但须要留神一种状况,会造成这种顺序控制的生效,当spring.factories定义的主动配置类,可能被应用了 @SpringBootApplication 润饰的启动类间接扫描到bean时,或者应用了@ComponentScan 间接扫描到了这些主动配置类,那它们就会被优先加载,忽视你配置的 @AutoConfigureBefore@AutoConfigureAfter等程序配置。