1 简述
通过前面几篇文章,尤其下面三篇,我已经对单实例bean的创建+初始化过程做了比较详细的介绍(之后可能还会进一步细化)。
《【spring】详解InitializingBean、initMethod和@PostConstruct》
《【bean的生命周期】— 对象创建+初始化流程分析 — 【重点@Autowired的作用时机】》
《【bean的生命周期】— 构造方法、@Autowired、BeanPostProcessor、InitializingBean等的执行顺序解析》
在《【bean的生命周期】— 对象创建+初始化流程分析 — 【重点@Autowired的作用时机】》那篇文章里讲到在spring环境下bean的生命周期大致可以分为下面三种情况:
(1)多实例:bean的创建、初始化在bean被使用的时候,bean的销毁由JVM的垃圾回收器进行处理。
(2)单实例懒加载的bean(注意
:懒加载一般指的是单实例bean):创建、初始化在bean第一次被使用的时候,之后便和单实例bean一样了,销毁在IOC容器关闭的时候。
(3)单实例bean:bean的创建、初始化在项目启动时,销毁在IOC容器关闭时。
在前面几篇文章里讲了单实例bean的创建+初始化,本篇文章将来讲一下bean的销毁,并在此基础上来验证一下上面的结论。
2 DisposableBean、destroyMethod和@PreDestroy介绍
DisposableBean、destroyMethod和@PreDestroy的作用时机在bean被销毁之前,我觉得它们三个正好可以和InitializingBean、initMethod和@PostConstruct进行一一对应:
InitializingBean—使用方法:实现InitializingBean接口,重写afterPropertiesSet方法,作用在bean初始化过程中
DisposableBean—使用方法:实现DisposableBean接口,重写destroy方法,作用在bean销毁之前
initMethod—使用方法:@Bean注入对象时,通过@Bean(initMethod = “init”)的方式,使当前bean中的init方法在bean初始化过程中被调用
destroyMethod—使用方法:@Bean注入对象时,通过@Bean(destroyMethod= “destroyMethod”)的方式,使当前bean中的destroyMethod方法在bean销毁之前被调用
@PostConstruct—JSR250定义的java规范,使用方法:直接在类中的某个方法上加上该注解,使该方法在bean初始化时被调用
@PreDestroy—JSR250定义的java规范,使用方法:直接在类中的某个方法上加上该注解,使该方法在bean销毁前被调用
3 测试
3.1 测试代码
- 实体类 — Cat
package com.nrsc.springstudy.c074DisposableBean_destroyMothod_PreDestroy.beans;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class Cat implements InitializingBean, DisposableBean {
private String name;
/***
* 构造方法-----创建对象时调用
*/
public Cat() {
System.out.println("Cat......constructor............");
}
/***
* 设置name属性时会调用
* @param name
*/
public void setName(String name) {
System.out.println("===cat=========setName========");
this.name = name;
}
public String getName() {
return name;
}
/***
* 在配置类中利用注解将initMethod指向下面的init方法----对应于initMethod的用法
*/
public void init() {
System.out.println("Cat......init............");
}
/***
* 在配置类中利用注解将destroyMethod指向下面的destroy方法----对应于destroyMethod的用法
*/
public void destroyMethod() {
System.err.println("cat....destroyMethod.....");
}
/***
* 继承了InitializingBean接口,需要实现afterPropertiesSet方法---对应于InitializingBean的用法
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Cat......afterPropertiesSet............");
}
/***
* 继承了DisposableBean接口,需要实现destroy方法---对应于DisposableBean的用法
*/
@Override
public void destroy() throws Exception {
System.err.println("Cat......DisposableBean............");
}
@PostConstruct
public void init2() {
System.out.println("Cat......@PostConstruct............");
}
@PreDestroy
public void destroy2() {
System.err.println("Cat......@PreDestroy............");
}
}
与此几乎相同的类还有三个分别为Duck、Monkey、Dog和Pig,这里不再列出。
- 将实体类注入到IOC容器中的代码
/***
* 单实例非懒加载的bean
* @return
*/
@Bean(initMethod = "init", destroyMethod = "destroyMethod")
public Cat buildCat() {
Cat cat = new Cat();
cat.setName("花花");
return cat;
}
/****
* 单实例且懒加载的bean --- 使用
* @return
*/
@Lazy
@Bean(initMethod = "init", destroyMethod = "destroyMethod")
public Duck duck() {
Duck duck = new Duck();
duck.setName("小黄鸭");
return duck;
}
/***
* 单实例且懒加载的bean --- 不使用
* @return
*/
@Lazy
@Bean(initMethod = "init", destroyMethod = "destroyMethod")
public Monkey monkey() {
Monkey monkey = new Monkey();
monkey.setName("小黄鸭");
return monkey;
}
/***
* 多实例bean --- 但不使用
* @return
*/
@Scope("prototype")
@Bean(initMethod = "init", destroyMethod = "destroyMethod")
public Dog dog() {
Dog dog = new Dog();
dog.setName("阿黄");
return dog;
}
/***
* 多实例bean --- 使用
* @return
*/
@Scope("prototype")
@Bean(initMethod = "init", destroyMethod = "destroyMethod")
public Pig pig() {
Pig pig = new Pig();
pig.setName("八戒");
return pig;
}
- 容器启动代码
@Test
public void test01() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(C074Config.class);
System.out.println("IOC容器创建完成........");
//使用懒加载的bean -- duck
Duck duck = (Duck) ac.getBean("duck");
//使用多实例的bean -- pig
Pig pig = (Pig) ac.getBean("pig");
ac.close();
}
3.2测试结果和结论
由运行结果正好可以得到如下结论:
(1)多实例:bean的创建、初始化在bean被使用的时候,bean的销毁由JVM的垃圾回收器进行处理。
(2)单实例懒加载的bean(注意
:懒加载一般指的是单实例bean):创建、初始化在bean第一次被使用的时候,之后便和单实例bean一样了,销毁在IOC容器关闭的时候。
(3)单实例bean:bean的创建、初始化在项目启动时,销毁在IOC容器关闭时。
4 简单分析一下容器关闭,bean销毁的源代码
容器关闭之前,spring会销毁所有的单实例bean,销毁逻辑主要如下: