在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); }}
启动之后执行TestService
的test
办法,失去如下程序的日志:
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
等程序配置。