踩坑:@PostConstruct、@DependsOn、@Order注解嵌套使用解决Bean加载优先级问题

简介: 踩坑:@PostConstruct、@DependsOn、@Order注解嵌套使用案例

今天在工作中写需求代码时,遇到的一个关于Sping Bean对象加载优先级问题,结合了Spring源码,大概总结了一下遇到Bean加载顺序需求问题时,比较常用的3个注解:@PostConstruct、@DependsOn、@Order

一、@Order注解的作用

  • @Order注解的作用是定义Spring IOC容器中Bean的执行顺序的优先级。

使用案例:

@Component
@Order(0)
public class Test01 {
   ...
}
@Component
@Order(1)
public class Test02 {
   ...
}
@Component
@Order(2)
public class Test03 {
   ...
}

如上述代码所示,通过@Order注解定义优先级,3个Bean对象从IOC容器中的加载顺序为:Test01、Test02、Test03。


二、@PostConstruct注解的作用

@PostConstruct注解可以用于修饰一个非静态的、返回值类型为 void 的方法(eg:myInit())。

该方法(myInit())会在服务器加载Servlet的时候被执行,且只会被执行一次!

该方法(myInit())的调用执行在构造函数之后,在Servlet的 init() 方法之前,在Servlet的 destroy()方法之后。

使用案例:

@Component
public class Test {
   @PostConstruct
   private void init() {
      // 初始化
      System.out.println("World!");
   } 
   public Test(){
       System.out.println("Hello");
   }
}

输出结果:

Hello
World!

三、@DependsOn注解的作用

该注解的作用顾名思义,就是 “谁依赖谁”。

假如在Test02类上加上@DependsOn(value = "test01"),那么就说明Test02在加载时,要依赖于Test01,Spring IOC 容器会优先加载Test01,然后再加载Test02。

举个实际业务场景的案例,假设现在有2个类Test01、Test02,需要交给Spring IOC容器托管:

/**
 * Test01是一个拥有1个静态变量的类
 */
@Component
public class Test01 {
    // 该静态变量的属性值需要通过Spring容器赋值,值(hello)定义在application.properties中。
    // 注意:@Value注解不可以给静态变量注入属性值 (否则获取的注入结果为null) !
    // 因此HELLO的属性值注入要在setter方法上加上@Value注解,参考文章:【https://blog.csdn.net/weixin_43591980/article/details/121503720】
    public static String HELLO;
    public static String WORLD;
    @Value("${spring.test.hello}")// 值为hello
    public void setHELLO(String hello) {
        HELLO = hello;
    }
    @Value("${spring.test.world}")// 值为world
    public void setWORLD(String world) {
        WORLD = easak;
    }
}

再来看Test02类的代码(前提要求:Test02类需要在我们的Spring Boot项目启动时首先被初始化调用!):

/**
 * Test02拥有一个@PostConstruct注解修饰的init()初始化方法和无参构造函数
 */
@Component
public class Test02 {
    @PostConstruct
    public void init(){
       ...
    }
    public Test02(){
        ... 
    }
}

业务需求:我需要在Test02的无参构造方法加载时,控制台打印Test01类中的HELLO静态变量值,然后在 init()方法执行时,控制台打印Test01类中的WORLD静态变量值。

刚开始我的第一想法是,直接这样写就好了:

@PostConstruct
public void init(){
   System.out.println(Test01.HELLO);
}
public Test02(){
    System.out.println(Test02.WORLD);
}


但是最终控制台打印的结果为:

null
null

Why?为什么是这个结果?

因为,Test02类会在我们的Spring Boot项目启动时首先被初始化调用,也就是说IOC容器会首先去加载Test02对象,而这时候Test01还尚未被加载到容器中,这时候Test01中的两个静态变量HELLO、WORLD还没有通过@Value注解注入属性值,所以结果理所应当是输出 null ~

解决方案:使用@DependsOn注解

我们对Test02类进行改进

@Component
@DependsOn(value = "test01")// 通过该注解,向Spring容器声明,该类的加载需要依赖于Test01,当加载Test02时,要先去加载Test01!
public class Test02 {
    @PostConstruct
    public void init(){
       System.out.println(Test01.HELLO);
    }
    public Test02(){
        System.out.println(Test01.WORLD);
    }
}


查看打印结果:

hello
world

注:也可以使用@Order注解给Test01、Test02类声明加载优先级,优先加载Test01,然后再加载Test02!

相关文章
feign使用url参数传参@SpringQueryMap使用
feign使用url参数传参@SpringQueryMap使用
275 0
|
前端开发 网络协议 Dubbo
超详细Netty入门,看这篇就够了!
本文主要讲述Netty框架的一些特性以及重要组件,希望看完之后能对Netty框架有一个比较直观的感受,希望能帮助读者快速入门Netty,减少一些弯路。
92511 32
超详细Netty入门,看这篇就够了!
|
XML SQL Java
Mybatis之转义符的使用姿势
在 mybatis 的 xml 文件中直接写 sql 比较方便简洁,但是需要注意的是,在 xml 文件中,经常会遇到一些需要转义的场景,比如查询 id < xxx的数据,这个小于号就不能直接写在 sql 中,接下来我们将看一下,mybatis 中的有哪些转义符,可以怎么处理转义问题
1001 0
Mybatis之转义符的使用姿势
|
缓存 JavaScript Cloud Native
阿里云发布 Spring Boot 新脚手架,真香
本文,围绕 spring initializr 框架,以 start.spring.io 为例,全面的给大家介绍如何使用和扩展这个框架,以及背后的运行原理。
57639 1
阿里云发布 Spring Boot 新脚手架,真香
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
1809 2
|
JSON Unix 测试技术
Wrk压测发送Post请求的正确姿势
这篇文章是关于如何使用Wrk工具进行HTTP基准测试的指南,包括Wrk的安装、基本用法、执行Get和Post请求的示例,以及在进行Post请求测试时正确设置Lua脚本的重要性。
950 1
|
6月前
|
存储 安全 IDE
说一说序列化与反序列化中存在的问题
本文详细解析了Java中的序列化机制,包括序列化的概念、实现方式及应用场景。通过Student类的实例演示了对象的序列化与反序列化过程,并分析了`Serializable`接口的作用以及`serialVersionUID`的重要意义。此外,文章还探讨了如何通过自定义`readObject()`方法增强序列化的安全性,以及解决可序列化单例模式中可能产生的多实例问题。最后提供了代码示例和运行结果,帮助读者深入理解序列化的原理与实践技巧。
158 2
|
11月前
|
Unix Linux 虚拟化
VMware Workstation 17.6.2 发布下载,现在完全免费无论个人还是商业用途
VMware Workstation 17.6.2 发布下载,现在完全免费无论个人还是商业用途
49443 16
VMware Workstation 17.6.2 发布下载,现在完全免费无论个人还是商业用途
|
10月前
|
网络协议 C# 开发工具
C#中简单Socket编程
1. 先运行服务器代码。服务器将开始监听指定的IP和端口,等待客户端连接。 1. 然后运行客户端代码。客户端将连接到服务器并发送消息。 1. 服务器接收到消息后,将回应客户端,并在控制台上显示接收到的消息。 1. 客户端接收到服务器的回应消息,并在控制台上显示。
462 15
|
JavaScript Java Maven
理解固化的Maven依赖:spring-boot-starter-parent 与 spring-boot-dependencies
理解固化的Maven依赖:spring-boot-starter-parent 与 spring-boot-dependencies
6465 1