简单介绍@PostConstruct@PreDestroy@DependsOn@Order等注解的作用及嵌套使用时优先级问题
Posted 一宿君
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单介绍@PostConstruct@PreDestroy@DependsOn@Order等注解的作用及嵌套使用时优先级问题相关的知识,希望对你有一定的参考价值。
简单介绍@PostConstruct、@PreDestroy、@DependsOn、@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
@Autowired
private B b;
public A()
System.out.println("执行A的构造函数,此时b还未被注入,b=" + b);
@PostConstruct
public 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
@PostConstruct
public void init()
public Test02()
业务需求:我需要在Test02的无参构造方法加载时,控制台打印Test01类中的HELLO静态变量值,然后在 init()方法执行时,控制台打印Test01类中的WORLD静态变量值。
最初的简单想法如下:
@Component
public class Test02
@PostConstruct
public void init()
System.out.println("2:" + Test01.HELLO);
public Test02()
System.out.println("1:" + Test01.WORLD);
此时运行Spring容器,查看控制台结果:
1:null
2:null
为什么会出现这种情况呢?原因就是因为我们在Test02类中调用Test01类中的静态变量时,Test01类即使是和Test02类同时注入Spring容器中,微观上可以认为是同步的,所以在Test02类去调用Test01类中的静态变量时,HELLO
和WORLD
的值还没有被@Value
注解加载注入,所以会打印null值。
解决办法:就是使用@DependOn(value = “test01”)注解!
@Component
@DependsOn(value = "test01")
public class Test02
@PostConstruct
public void init()
System.out.println("2:" + Test01.HELLO);
public Test02()
System.out.println("1:" + Test01.WORLD);
再次运行Spring容器,查看控制台结果:
#这样值就有了,意思是运行Test02类时,知道Test02中调用了Test01类的资源了,所以先去加载Test01类
1: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
注解也可以实现。
以上是关于简单介绍@PostConstruct@PreDestroy@DependsOn@Order等注解的作用及嵌套使用时优先级问题的主要内容,如果未能解决你的问题,请参考以下文章