在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 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
而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-boot中的@Order怎么用】但需要注意一种情况,会造成这种顺序控制的失效,当spring.factories定义的自动配置类,能够被使用了
@SpringBootApplication
修饰的启动类直接扫描到bean时,或者使用了@ComponentScan
直接扫描到了这些自动配置类,那它们就会被优先加载,无视你配置的 @AutoConfigureBefore
、@AutoConfigureAfter
等顺序配置。推荐阅读
- springboot|在SpringBoot中读取yaml配置文件中的数据、全部数据、部分数据
- Nacos|二、SpringCloud框架搭建之Nacos配置中心
- springboot|企业微信通过群聊机器人用springboot发送信息
- springcloud|医院项目-预约挂号-第八部分手机登录
- BUG小王子|String转Date问题
- RabbitMQ|消息中间件RabbitMQ(五)——实现RPC调用
- springboot|一文详解Spring、SpringBoot、Springcloud的关系与区别
- #|SpringBoot2学习笔记一--Spring与SpringBoot2
- Java基础|spring/spring boot 自定义日志注解输出请求参数和结果