当前位置: 代码迷 >> 综合 >> 简单介绍@PostConstruct、@PreDestroy、@DependsOn、@Order等注解的作用及嵌套使用时优先级问题
  详细解决方案

简单介绍@PostConstruct、@PreDestroy、@DependsOn、@Order等注解的作用及嵌套使用时优先级问题

热度:38   发布时间:2023-11-24 10:37:58.0

简单介绍@PostConstruct、@PreDestroy、@DependsOn、@Order等注解的作用及嵌套使用时优先级问题

  • 1、@PostConstruct和@PreDestroy注解
  • 2、@DependsOn注解
  • 3、@Order注解

1、@PostConstruct和@PreDestroy注解

说明:@PostConstruct注解好多人以为是Spring提供的,其实是Java自己的注解。

从JavaEE5规范开始,Servlet中增加了两个影响Servlet生命周期的注解,@PostConstruct@PreDestroy这两个注解被用来修饰一个非静态的void()方法,并且被修饰的方法不能抛出异常。

被@PostContruct注解的方法:

  • 会在服务器加载Servlet的时候运行,并且只会被服务器执行一次,具体运行时期是在构造函数执行之后,init()初始化方法之前。

  • 通常我们会在Spring框架中使用@postConstruct注解,该注解的方法在整个Bean初始化中的顺序:Constructor(构造方法)->@Autowired(依赖注入)->@PostConstruct(注释的方法)

  • 该注解的用法:

    @PostConstruct
    public void method(){
          }
    
  • 或者:

    public @PostConstruct	 void method(){
          }
    

被@PreDestroy修饰的方法:

  • 会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法,会在destroy()方法之后运行,在Servlet被彻底卸载之前。

执行大致流程图:

**加粗样式**

被注解的Servlet生命周期:

  • 需要注意的是,注解会多多少少地影响到服务器的启动速度。服务器在启动时候会遍历Web 应用的WEB-INF/classes下的所有class文件与WEB-INF/lib下的所有jar文件,以检查哪些类使用了注解。

  • 如果应用程序中没有 使用任何注解,可以在Web.xml中设置metadata-complete属性为true。

  • 支持@PostConstruct和@PreDestroy注解的服务器需要支持Servlet2.5规范,Tomcat5.x仅支持Servlet2.4规范。

@PostContruct注解的方法,Spring中如何发现?

其实在Bean依赖注入也会经常用到,比如所有这样一个场景:

要将对象B注入到对象A,那么首先就必须得生成对象A和对象B,才能执行注入。

  • 如果一个类A中有个成员变量b被@Autowried注解,那么@Autowired注入是发生在A的构造方法执行完之后的。
  • 如果想在生成对象时完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。

实例演示:

A类:

@Component
public class A {
    @Autowiredprivate B b;public A(){
    System.out.println("执行A的构造函数,此时b还未被注入,b=" + b);}@PostConstructpublic void init(){
    System.out.println("@PostConstruct注解此方法,会在对象b注入完成之后自动调用此方法,b=" + b);}
}

B类:

@Component
public class B {
    public B(){
    System.out.println("执行B的构造函数!");}
}

直接运行Spring容器,查看结果:

执行A的构造函数,此时b还未被注入,b=null
执行B的构造函数!
@PostConstruct注解此方法,会在对象b注入完成之后自动调用此方法,b=cn.wbs.test.B@265adfad

2、@DependsOn注解

该注解的作用:

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

参考文章:https://blog.csdn.net/weixin_43591980/article/details/121547379?spm=1001.2014.3001.5501

实例演示:假设现在有2个类Test01、Test02,需要交给Spring IOC容器托管:

  • 静态变量的属性值需要通过Spring容器赋值,值(hello和world)定义在application.properties中。
  • 注意:@Value注解不可以给静态变量注入属性值 (否则获取的注入结果为null)。
  • 所以需要再setter方法上标注注入值,setter方法也是不可以加static关键字的
@Component
public class Test01 {
    public static String HELLO;public static String WORLD;@Value("${spring.test.hello}")public void setHELLO(String HELLO) {
    Test01.HELLO = HELLO;}@Value("${spring.test.world}")public void setWORLD(String WORLD) {
    Test01.WORLD = WORLD;}
}
@Component
public class Test02 {
    @PostConstructpublic  void init(){
    }public Test02(){
    }
}

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

最初的简单想法如下:

@Component
public class Test02 {
    @PostConstructpublic  void init(){
    System.out.println("2:" + Test01.HELLO);}public Test02(){
    System.out.println("1:" + Test01.WORLD);}
}

此时运行Spring容器,查看控制台结果:

1null
2null

为什么会出现这种情况呢?原因就是因为我们在Test02类中调用Test01类中的静态变量时,Test01类即使是和Test02类同时注入Spring容器中,微观上可以认为是同步的,所以在Test02类去调用Test01类中的静态变量时,HELLOWORLD的值还没有被@Value注解加载注入,所以会打印null值。

解决办法:就是使用@DependOn(value = “test01”)注解!

@Component
@DependsOn(value = "test01")
public class Test02 {
    @PostConstructpublic  void init(){
    System.out.println("2:" + Test01.HELLO);}public Test02(){
    System.out.println("1:" + Test01.WORLD);}
}

再次运行Spring容器,查看控制台结果:

#这样值就有了,意思是运行Test02类时,知道Test02中调用了Test01类的资源了,所以先去加载Test011:WORLD
2:HELLO

3、@Order注解

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

实例演示:

@Component
@Order(1)
public class Test01 {
    System.out.println("执行Test01类");
}@Component
@Order(2)
public class Test02 {
    System.out.println("执行Test02类");
}

运行spring容器,查看控制台结果:

执行Test01类
执行Test02

如上述代码所示,通过@Order注解定义优先级,2个Bean对象从IOC容器中的加载顺序为:Test01、Test02,实际上上述演示的业务需求使用@Order注解也可以实现。

  相关解决方案