共计 3374 个字符,预计需要花费 9 分钟才能阅读完成。
在 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 bean1
post bean1
initialled bean1
construct bean2
post bean2
initialled 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
@RequiredArgsConstructor
public class TestService {
private final List<IBean> beans;
public void test(){beans.forEach(IBean::work);
}
}
启动之后执行 TestService
的test
办法,失去如下程序的日志:
construct bean1
post bean1
initialled bean1
construct bean2
post bean2
initialled bean2
running bean2
running bean1
bean2 is working
bean1 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
等程序配置。