在网上查询 Bean 的加载顺序时,看到了大量的文章中使用@Order注解的方式来控制 bean 的加载顺序,不知道写这些的博文的同学自己有没有实际的验证过,本文希望通过指出这些错误的使用姿势,让观文的小伙伴可以知道@Order的具体的应用场景
原文地址:
I. 环境搭建创建一个 maven 项目,pom 文件如下(具体的项目代码,可以在文末获取)
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7</version> <relativePath/> <!-- lookup parent from update --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </pluginManagement> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> II. 错误姿势下面我们会介绍两种典型注解的错误使用姿势,一个@Order,一个@AutoConfigureOrder
I. @Order err.case1: 类上添加 Order 注解一种常见的错误观点是在类上添加这个 Order 注解,就可以指定 bean 之间的初始化顺序,order 值越小,则优先级越高,接下来我们实际测试一下,是否如此
我们创建两个 DemoBean, 指定不同的 Order 顺序
@Order(4) @Component public class BaseDemo1 { private String name = "base demo 1"; public BaseDemo1() { System.out.println(name); } } @Order(3) @Component public class BaseDemo2 { private String name = "base demo 2"; public BaseDemo2() { System.out.println(name); } }根据前面的观点,orde 值小的优先级高,那么 BaseDemo2 应该先被初始化,实际测试一下,输出如下
err.case2: 配置类中 Bean 声明方法上添加@OrderBean 除了上面的自动扫描之外,还有一种方式就是通过@Bean注解,下面我们演示一下在配置类中指定 bean 加载顺序的错误 case
同样我们新建两个测试 bean
public class BaseDemo3 { private String name = "base demo 3"; public BaseDemo3() { System.out.println(name); } } public class BaseDemo4 { private String name = "base demo 4"; public BaseDemo4() { System.out.println(name); } }接下来在配置类中定义 bean
@Configuration public class ErrorDemoAutoConf { @Order(2) @Bean public BaseDemo3 baseDemo3() { return new BaseDemo3(); } @Order(1) @Bean public BaseDemo4 baseDemo4() { return new BaseDemo4(); } }同样的,如果@Order注解有效,那么BaseDemo4应该先被初始化
从上面的实际测试输出可以看出,@Order 注解在上面的方式中也不生效,如果有兴趣的同学可以试一下,将上面配置类中的两个方法的顺序颠倒一下,会发现BaseDemo4先加载
err.case3: @Order 注解修饰配置类这也是一种常见的错误 case,认为@Order 注解是用来指定配置类的加载顺序的,然而真的是这样么?
我们创建两个测试的配置类
@Order(1) @Configuration public class AConf { public AConf() { System.out.println("AConf init!"); } } @Order(0) @Configuration public class BConf { public BConf() { System.out.println("BConf init"); } }如果@Order 注解生效,那么 BConf 配置类会优先初始化,那么我们实测一下
从上面的结果可以看出,并不是 BConf 先被加载;当然这种使用姿势,实际上和第一种错误 case,并没有什么区别,配置类也是 bean,前面不生效,这里当然也不会生效
那么是不是我们的理解不对导致的呢,实际上这个@Order放在配置类上之后,是这个配置类中定义的 Bean 的优先于另一个配置类中定义的 Bean 呢?
同样的我们测试下这种 case,我们定义三个 bean,两个 conf
public class Demo1 { private String name = "conf demo bean 1"; public Demo1() { System.out.println(name); } } public class Demo2 { private String name = "conf demo bean 2"; public Demo2() { System.out.println(name); } } public class Demo3 { private String name = "conf demo bean 3"; public Demo3() { System.out.println(name); } }