本篇介绍Spring框架为Spring Bean生命周期各阶段提供的回调接口,程序通过实现回调接口,可以在IOC容器实例化或销毁Bean的过程中,得到Bean的控制权,并对Bean进行预处理工作。通过本篇的学习,可以达成如下目标。
● 了解Spring Bean的生命周期
● 掌握和运用Spring Bean生命周期各阶段提供的接口
● 能够对Spring Bean做预处理工作
Spring Bean虽然由IOC容器管理,不需要程序过多干预。但在一些情况下,程序可能需要在容器之外,对Bean进行一些处理工作。如IOC容器实例化Bean时,程序对Bean进行一些初始化工作,或者IOC容器销毁Bean时,程序对Bean做一些数据的保存或清除工作。
Spring Bean从创建、运行到销毁经历了若干阶段,在Bean生命周期的每个阶段,程序都可以通过初始化回调、在配置文件中声明方法、前置或后置处理等技术获取Bean的控制权,对Bean进行处理工作。Bean生命周期的各个阶段如下图所示。
图 1 Spring Bean生命周期
一、回调Aware接口
当Spring IOC容器内的Bean对象实例化完成并且相关属性以及依赖设置完成后,IOC容器会检查当前Bean对象是否实现Aware接口,如果实现了Aware接口,则调用Bean已经实现的Aware接口。Bean通过实现这些接口,可以增强Bean的功能,但是也增加了对Spring容器的依赖。
表 1 可以实现的Aware接口列表

例1:实现BeanNameAware接口
修改课程案例Teacher类,实现BeanNameAware接口。
package com.milihua.springprogram.entity;
import org.springframework.beans.factory.BeanNameAware;
public class Teacher implements BeanNameAware{
private String name;
private String classtime;
public String getNotify() {
return name + "在" + classtime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClasstime() {
return classtime;
}
public void setClasstime(String classtime) {
this.classtime = classtime;
}
@Override
public void setBeanName(String arg0) {
// TODO Auto-generated method stub
System.out.println("BeanNameAware:Bean name is" +arg0);
}
}
setBeanName为实现的接口,接口简单输出bean的名称。运行结果如下图所示。

图 2 Teacher类输出Bean的名称
从输出结果可以看出,Teacher类实现了BeanNameAware接口后,IOC容器将回调Bean实现的BeanNameAware接口的setBeanName方法。
前置处理和后置处理器BeanPostProcessor
前置处理是指程序在Spring IOC容器初始化Bean之前、属性设置之后对该Bean先做一些预处理工作。Spring提供了BeanPostProcessors接口,Bean通过实现该接口的postProcessBeforeInitialization和postProcessAfterInitialization方法,可以在Bean初始化之前或初始化之后做前置处理和后置处理操作。
例2:实现BeanPostProcessor的前置和后置接口
修改课程案例Teacher类,实现postProcessBeforeInitialization前置接口和postProcessAfterInitialization后置接口。
package com.milihua.springprogram.entity;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class Teacher implements BeanNameAware,BeanPostProcessor{
private String name;
private String classtime;
public String getNotify() {
return name + "在" + classtime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClasstime() {
return classtime;
}
public void setClasstime(String classtime) {
this.classtime = classtime;
}
@Override
public void setBeanName(String arg0) {
// TODO Auto-generated method stub
// System.out.println("BeanNameAware:Bean name is" +arg0);
}
// Bean 实例化之前进行的处理
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor.postProcessBeforeInitialization 初始化前预处理,开始实例化");
System.out.println("...........");
System.out.println("...........");
System.out.println("...........");
return bean;
}
// Bean 实例化之后进行的处理
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor.postProcessAfterInitialization 初始化后预处理,实例化完成");
return bean;
}
}
建立beanpost.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<bean id="teacher" scope="prototype" class="com.milihua.springprogram.entity.Teacher">
<property name="name" value="张老师"></property>
</bean>
</beans>
建立BeanPostTest类文件。
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.milihua.springprogram.entity.Teacher;
public class BeanPostTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context = new ClassPathXmlApplicationContext("config/beanpost.xml");
//从容器中获取张老师的实例
Teacher teacherZhang = context.getBean("teacher",Teacher.class);
}
}
执行BeanPostTest类文件,输出结果如下图所示。

图 3 实现BeanPostProcessor接口输出结果
二、回调InitializingBean接口
InitializingBean接口为Bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化Bean的时候会执行该方法。
例3:实现InitializingBean接口
修改课程案例Teacher类,实现InitializingBean接口的afterPropertiesSet方法。
package com.milihua.springprogram.entity;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class Teacher implements BeanNameAware,BeanPostProcessor,InitializingBean{
private String name;
private String classtime;
public String getNotify() {
return name + "在" + classtime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClasstime() {
return classtime;
}
public void setClasstime(String classtime) {
this.classtime = classtime;
}
@Override
public void setBeanName(String arg0) {
// TODO Auto-generated method stub
// System.out.println("BeanNameAware:Bean name is" +arg0);
}
// Bean 实例化之前进行的处理
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor.postProcessBeforeInitialization 初始化前预处理,开始实例化");
System.out.println("...........");
System.out.println("...........");
System.out.println("...........");
return bean;
}
// Bean 实例化之后进行的处理
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor.postProcessAfterInitialization 初始化后预处理,实例化完成");
return bean;
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("afterPropertiesSet 正在初始化.....");
}
}
配置init-method方法
在Spring配置文件中,可以使用 init-method 属性来指定带有 void 无参数方法的名称,该方法在Bean实例完成创建后调用。
例4:实现init-method方法
修改beanpost.xml配置文件,在配置文件中添加init-method属性。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<bean id="teacher" init-method="init" scope="prototype" class="com.milihua.springprogram.entity.Teacher">
<property name="name" value="张老师"></property>
</bean>
</beans>
修改Teacher类,添加init方法。
//init方法
public void init() {
// do some initialization work
System.out.println("init.......");
}
执行BeanPostTest文件,输出结果如下图所示。

图 4 配置init-method方法输出结果
从上图可以看出,实现InitializingBean接口的afterPropertiesSet方法首先被调用,然后init方法被调用。
三、回调DisposableBean接口
DisposableBean接口为释放Bean提供了释放资源的方法,它只包括destory方法,凡是继承该接口的类,在释放Bean的时候会执行该方法。
例5:实现DisposableBean接口
修改课程案例Teacher类,实现DisposableBean接口的destroy方法。
package com.milihua.springprogram.entity;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class Teacher implements BeanNameAware,BeanPostProcessor,InitializingBean,DisposableBean{
private String name;
private String classtime;
public String getNotify() {
return name + "在" + classtime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClasstime() {
return classtime;
}
public void setClasstime(String classtime) {
this.classtime = classtime;
}
@Override
public void setBeanName(String arg0) {
// TODO Auto-generated method stub
// System.out.println("BeanNameAware:Bean name is" +arg0);
}
//init方法
public void init() {
// do some initialization work
System.out.println("init.......");
}
// Bean 实例化之前进行的处理
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor.postProcessBeforeInitialization 初始化前预处理,开始实例化");
System.out.println("...........");
System.out.println("...........");
System.out.println("...........");
return bean;
}
// Bean 实例化之后进行的处理
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor.postProcessAfterInitialization 初始化后预处理,实例化完成");
return bean;
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("afterPropertiesSet 正在初始化后.....");
}
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("destroy 正在释放资源.....");
}
}
配置destroy-method方法
在Spring配置文件中,可以使用 destroy-method 属性来指定带有 void 无参数方法的名称,该方法在Bean实例销毁后调用。
例5:实现destroy-method方法
修改beanpost.xml配置文件,在配置文件中添加destroy-method属性。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<bean id="teacher" destroy-method="destroy_mehtod" init-method="init" scope="prototype" class="com.milihua.springprogram.entity.Teacher">
<property name="name" value="张老师"></property>
</bean>
</beans>
修改Teacher类,添加destroy_mehtod方法。
// destroy_mehtod方法
public void destroy_mehtod () {
// do some initialization work
System.out.println("destory.......");
}
课程小结
IOC容器创建Bean并设置Bean属性后,将执行以下操作:
(1)检查Aware接口,如果Bean实现了Aware接口,则执行回调;
(2)检查和回调BeanPostProcessor的前置处理接口;
(3)执行Bean的初始化工作,并调用InitializingBean接口,如果在配置文件中Bean定义了init-method属性,则同时调用init-method属性指定的方法;
(4)Bean初始化完成后,IOC容器会调用BeanPostProcessor的后置处理接口;
(5)Bean进入运行阶段;
(6)Bean被销毁时调用DisposableBean接口,如果在配置文件中Bean定义了destroy_mehtod属性,则同时调用destroy_mehtod属性指定的方法。