注解@PostConstruct与@PreDestroy使用讲解

1、简介

从JavaEE5规范开始,Servlet增加了两个影响Servlet生命周期的注解(Annotation):@PostConstruct和@PreConstruct。这两个注解被用来修饰一个非静态的void()方法.而且这个方法不能有抛出异常声明。

Spring的@PostConstruct注解在方法上,表示此方法是在Spring实例化该Bean之后马上执行此方法,之后才会去实例化其他Bean,并且一个Bean中@PostConstruct注解的方法可以有多个。PostConstruct注解用于方法上,该方法在初始化的依赖注入操作之后被执行。这个方法必须在class被放到service之后被执行,这个注解所在的类必须支持依赖注入

首先,我们可以看到这个注解是在javax.annotation包下的,也就是java拓展包定义的注解并不是spring定义的,但至于为什么不在java包下,是因为java语言的元老们认为这个东西并不是java核心需要的工具,因此就放到扩展包里(javax中的x就是extension的意思),而spring是支持依赖注入的,因此spring必须要自己来实现@PostConstruct的功能。

@PostConstruct
Public void someMethod() {}
或者
public @PostConstruct void someMethod(){}

1.@PostConstruct说明
被@PostConstruct修饰的方法会在服务器加载Servlet(bean)的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法。被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。
用处: spring项目加载数据字典
@PostConstruct注解的方法在项目启动的时候执行这个方法,也可以理解为在spring容器启动的时候执行,可作为一些数据的常规化加载,比如数据字典之类的。

2.@PreDestroy说明
被@PreDestroy修饰的方法会在服务器卸载Servlet(bean)的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreDestroy修饰的方法会在destroy()方法之后运行,在Servlet被彻底卸载之前

2、关于在spring 容器初始化 bean 和销毁前所做的操作定义方式有三种:

参考

  • 第一种:通过 @PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作

  • 第二种是:通过 在xml中定义init-method 和 destory-method方法

  • 第三种是: 通过bean实现InitializingBean和 DisposableBean接口

@PostConstruct 和 @PreDestroy 标注不属于 Spring,它是在J2EE库- common-annotations.jar。

3、加载过程

构建顺序如下

构造器-->自动注入-->@PostConstrut-->InitializingBean-->xml中配置init方法  

销毁顺序如下

@PreDestroy--DisposableBean-->xml中destroy-method方法

加载过程:
注解@PostConstruct与@PreDestroy使用讲解_第1张图片
需要注意的是,注解会多多少少地影响到服务器的启动速度。服务器在启动时候会遍历Web 应用的WEB-INF/classes下的所有class文件与WEB-INF/lib下的所有jar文件,以检查哪些类使用了注解。如果应用程序中没有 使用任何注解,可以在Web.xml中设置的metadata-complete属性为true.(支持@PostConstruct和 @PreDestroy的服务器需要支持Servlet2.5规范。Tomcat5.x仅支持Servlet2.4规范。)

4、实例

特点:
1、只有一个非静态方法能使用此注解
2、被注解的方法不得有任何参数
3、被注解的方法返回值必须为void
4、被注解方法不得抛出已检查异常
5、此方法只会被执行一次

实例1:
参考 https://www.cnblogs.com/fnlingnzb-learner/p/10758848.html

public Class AAA{
        @Autowired
        private BBB b;

        public AAA() {
             System.out.println("此时b还未被注入: b = " + b);
        }
        @PostConstruct
        private void init () {
             System.out.println("@PostConstruct将在依赖注入完成后被自动调用: b = " + b);
        }
    }

实例2:父类、子类 参考

父类class,被@component注解修饰,说明会被spring扫描并创建。在默认构造方法里加上输出打印,init方法被@PostConstruct修饰

@Component
public class ParentBean implements InitializingBean{
	
	public ParentBean() {
		System.out.println("ParentBean construct");
	}
	
	@PostConstruct
	public void init(){
		System.out.println("ParentBean init");
	}

	public void afterPropertiesSet() throws Exception {
		System.out.println("ParentBean afterPropertiesSet");
	}
}

子类class,也被 @component注解修饰,其余配置和父类class一样

@Component
public class SonBean extends ParentBean{
	public SonBean() {
		System.out.println("SonBean construct");
	}
	
	@PostConstruct
	public void init(){
		System.out.println("SonBean init");
	}
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("SonBean afterPropertiesSet");
	}	
}

然后我们使用maven命令 jetty:run,控制台输出如下:

[INFO] Initializing Spring root WebApplicationContext
ParentBean construct
ParentBean init
ParentBean afterPropertiesSet

ParentBean construct
SonBean construct
SonBean init
SonBean afterPropertiesSet
[INFO] Set web app root system property: 'webapp.root' = [J:\androidworkspace\com\src\main\webapp\]
[INFO] Initializing log4j from [classpath:log4j.properties]
[INFO] Started [email protected]:8088
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 3 seconds.

结论:

  • 可以看出优先执行依然是构造方法,这个是java的语言决定的,毕竟spring只是建立在java之上的框架。
  • 然后才是被PostConstruct修饰的方法,要注意的是这个方法在对象的初始化和依赖都完成之后才会执行,所以不必担心执行这个方法的时候有个别成员属性没有被初始化为null的情况发生。
  • 在init方法之后执行的才是afterPropertiesSet方法,这个方法必须实现InitializingBean接口,这个接口很多spring的bean都实现了他,从他的方法名就能看出在属性都被设置了之后执行,也属于springbean初始化方法。

你可能感兴趣的:(Spring)