SpringBootBean指定初始化顺序详解
最近遇到SpringBoot容器外类初始化依赖容器内bean的问题,由于容器内bean初始化有⼀定顺序,⽹上查了查资料,这⾥记录⼀下。0. 前⾔
本⽂将介绍⼏种可⾏的⽅式来控制 bean 之间的加载顺序
@Order指明顺序
@AutoConfigureOrder
构造⽅法依赖
@DependOn 注解
BeanPostProcessor 扩展
1. @Order和@AutoConfigureOrder说明
1.1. 错误姿势
下⾯我们会介绍两种典型注解的错误使⽤姿势,⼀个@Order,⼀个@AutoConfigureOrder
1.1.1 @Order
err.case1: 类上添加 Order 注解
结论:Sprintboot默认⾃动扫描,order 值的⼤⼩,与指定 bean 之间的初始化顺序⽆关。
⼀种常见的错误观点是在类上添加这个 Order 注解,就可以指定 bean 之间的初始化顺序,order 值越⼩,则优先级越⾼,接下来我们实际测试⼀下,是否如此
我们创建两个 DemoBean, 指定不同的 Order 顺序
@Order(4)
@Component
publicclass BaseDemo1 {
private String name = "base demo 1";
public BaseDemo1() {
System.out.println(name);
}
}
@Order(3)
@Component
publicclass BaseDemo2 {
private String name = "base demo 2";
public BaseDemo2() {
System.out.println(name);
}
}
根据前⾯的观点,order值⼩的优先级⾼,那么 BaseDemo2 应该先被初始化,实际测试⼀下,输出如下
err.case2: 配置类中 Bean 声明⽅法上添加@Order
结论:通过@Bean注解扫描,order 值的⼤⼩,与指定 bean 之间的初始化顺序⽆关。
Bean 除了上⾯的⾃动扫描之外,还有⼀种⽅式就是通过@Bean注解,下⾯我们演⽰⼀下在配置类中指定 bean 加载顺序的错误 case
同样我们新建两个测试 bean
publicclass BaseDemo3 {
private String name = "base demo 3";
public BaseDemo3() {
System.out.println(name);
}
}
publicclass BaseDemo4 {
private String name = "base demo 4";
public BaseDemo4() {
System.out.println(name);
}
}
接下来在配置类中定义 bean
@Configuration
publicclass ErrorDemoAutoConf {
@Order(2)
@Bean
public BaseDemo3 baseDemo3() {
returnnew BaseDemo3();
}
@Order(1)
@Bean
public BaseDemo4 baseDemo4() {
returnnew BaseDemo4();
}
}
同样的,如果@Order注解有效,那么BaseDemo4应该先被初始化
从上⾯的实际测试输出可以看出,@Order 注解在上⾯的⽅式中也不⽣效,如果有兴趣的同学可以试⼀下,将上⾯配置类中的两个⽅法的顺序颠倒⼀下,会发现BaseDemo4先加载
err.case3: @Order 注解修饰配置类
结论:通过@Order 注解是⽤来指定配置类的加载顺序,初始化顺序与@Order⼤⼩值⽆关。
这也是⼀种常见的错误 case,认为@Order 注解是⽤来指定配置类的加载顺序的,然⽽真的是这样么?
我们创建两个测试的配置类
public AConf() {
System.out.println("AConf init!");
}springboot是啥
}
@Order(0)
@Configuration
publicclass BConf {
public BConf() {
System.out.println("BConf init");
}
}
如果@Order 注解⽣效,那么 BConf 配置类会优先初始化,那么我们实测⼀下
从上⾯的结果可以看出,并不是 BConf 先被加载;当然这种使⽤姿势,实际上和第⼀种错误 case,并没有什么区别,配置类也是 bean,前⾯不⽣效,这⾥当然也不会⽣效。
那么是不是我们的理解不对导致的呢,实际上这个@Order放在配置类上之后,是这个配置类中定义的 Bean 的优先于另⼀个配置类中定义的 Bean 呢?
同样的我们测试下这种 case,我们定义三个 bean,两个 conf
publicclass Demo1 {
private String name = "conf demo bean 1";
public Demo1() {
System.out.println(name);
}
}
publicclass Demo2 {
private String name = "conf demo bean 2";
public Demo2() {
System.out.println(name);
}
}
publicclass Demo3 {
private String name = "conf demo bean 3";
public Demo3() {
System.out.println(name);
}
}
然后我们将 Demo1, Demo3 放在⼀个配置中,Demo2 放在另外⼀个配置中
@Bean
public Demo1 demo1() {
returnnew Demo1();
}
@Bean
public Demo3 demo3() {
returnnew Demo3();
}
}
@Order(1)
@Configuration
publicclass BConf1 {
@Bean
public Demo2 demo2() {
returnnew Demo2();
}
}
如果@Order 注解实际上控制的是配置类中 Bean 的加载顺序,那么 BConf1 中的 Bean 应该优先加载,也就是说 Demo2 会优先于Demo1, Demo3,实际测试⼀下,输出如
上⾯的输出结果和我们预期的并不⼀样,所以@Order注解来决定配置类的顺序也是不对的
1.1.
2. @AutoConfigureOrder
从命名来看,这个注解是⽤来指定配置类的顺序的,然⽽对于这个注解的错误使⽤也是⾮常多的,⽽⼤多的错误使⽤在于没有真正的了解到它的使⽤场景
接下来我们来演⽰⼀下错误的使⽤ case
在⼯程内新建两个配置类,直接使⽤注解
@Configuration
@AutoConfigureOrder(1)
publicclass AConf2 {
public AConf2() {
System.out.println("A Conf2 init!");
}
}
@Configuration
@AutoConfigureOrder(-1)
publicclass BConf2 {
public BConf2() {
System.out.println("B conf2 init!");
}
}
当注解⽣效时,BConf 会优先级加载
从输出结果来看,和我们预期的不⼀样;那么这个注解是不是作⽤于配置类中的 Bean 的顺序,⽽不是配置类本⾝呢?同样的我们设计⼀个 case 验证⼀下
publicclass DemoA {
private String name = "conf demo bean A";
public DemoA() {
System.out.println(name);
}
}
publicclass DemoB {
private String name = "conf demo bean B";
public DemoB() {
System.out.println(name);
}
}
publicclass DemoC {
private String name = "conf demo bean C";
public DemoC() {
System.out.println(name);
}
}
对应的配置类

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。