第 10 章 Spring Bean 后置处理器
本章节主要介绍在《Spring 基础教程 (第 9 章) - Spring Bean 生命周期(1)》一章提到的 BeanPostProcessor
接口。 BeanPostProcessor
接口也被称为后置处理器,通过该接口可以自定义调用初始化前后执行的操作方法。
10. 1. BeanPostProcessor 接口
BeanPostProcessor
接口源码如下:
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
该接口中包含了两个方法:
postProcessBeforeInitialization()
方法:在 Bean 实例化、属性注入后,初始化前调用。postProcessAfterInitialization()
方法:在 Bean 实例化、属性注入、初始化都完成后调用。
当需要添加多个后置处理器实现类时,默认情况下 Spring 容器会根据后置处理器的定义顺序来依次调用。也可以通过实现 Ordered 接口的 getOrder 方法指定后置处理器的执行顺序。该方法返回值为整数,默认值为 0,取值越大优先级越低。
例 1
下面我们就来演示下 BeanPostProcessor 接口的用法,步骤如下:
创建命名为 Woman 的类,代码如下:
package section10.demo1;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* ClassName: Woman
* Description: TODO
*
* @author chuanlu
* @version 1.0.0
*/
public class Woman {
private static final Log LOGGER = LogFactory.getLog(Woman.class);
// 姓名
private String name;
// 年龄
private Integer age;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void init() {
LOGGER.info("Bean 正在初始化,开始梳妆打扮换衣服");
}
public void destroy() {
LOGGER.info("Bean 正在销毁,关灯睡觉");
}
@Override
public String toString() {
return "Woman{" +
"name='" + name + '\'' +
"age='" + age + '\'' +
'}';
}
}
创建命名为 MakeUp 的类,代码如下:
package section10.demo1;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
/**
* ClassName: MakeUp
* Description: TODO
*
* @author chuanlu
* @version 1.0.0
*/
public class MakeUp implements BeanPostProcessor, Ordered {
private static final Log LOGGER = LogFactory.getLog(MakeUp.class);
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LOGGER.info("准备化妆品 : " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
LOGGER.info("卸妆 : " + beanName);
return bean;
}
@Override
public int getOrder() {
return 0;
}
}
注意:postProcessBeforeInitialization()
和 postProcessAfterInitialization()
方法返回值不能为 null,否则会报空指针异常或者通过 getBean() 方法获取不到 Bean 实例对象。
创建命名为 DressUp 的类,代码如下:
package section10.demo1;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
/**
* ClassName: DressUp
* Description: TODO
*
* @author chuanlu
* @version 1.0.0
*/
public class DressUp implements BeanPostProcessor, Ordered {
private static final Log LOGGER = LogFactory.getLog(DressUp.class);
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LOGGER.info("准备约会服装 : " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
LOGGER.info("换睡衣 : " + beanName);
return bean;
}
@Override
public int getOrder() {
return 1;
}
}
修改 Spring 配置文件 spring-config.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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="woman" class="section10.demo1.Woman" init-method="init" destroy-method="destroy">
<property name="name" value="小丽"/>
<property name="age" value="24"/>
</bean>
<!-- 注册处理器 -->
<bean class="section10.demo1.MakeUp"/>
<bean class="section10.demo1.DressUp"/>
</beans>
创建命名为 MainApp 的类,代码如下:
package section10.demo1;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* ClassName: MainApp
* Description: TODO
*
* @author chuanlu
* @version 1.0.0
*/
public class MainApp {
private static final Log LOGGER = LogFactory.getLog(MainApp.class);
public static void main(String[] args) {
// 获取 ApplicationContext 容器
AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 获取名为 woman 的 Bean
Woman woman = context.getBean("woman", Woman.class);
// 日志输出对象信息
LOGGER.info(woman.toString());
//手动销毁 Bean
context.close();
}
}
执行 MainApp 中的 main 方法,控制台输出如下:
4月 08, 2022 7:23:57 下午 section10.demo1.MakeUp postProcessBeforeInitialization
信息: 准备化妆品 : woman
4月 08, 2022 7:23:57 下午 section10.demo1.DressUp postProcessBeforeInitialization
信息: 准备约会服装 : woman
4月 08, 2022 7:23:57 下午 section10.demo1.Woman init
信息: Bean 正在初始化,开始梳妆打扮换衣服
4月 08, 2022 7:23:57 下午 section10.demo1.MakeUp postProcessAfterInitialization
信息: 卸妆 : woman
4月 08, 2022 7:23:57 下午 section10.demo1.DressUp postProcessAfterInitialization
信息: 换睡衣 : woman
4月 08, 2022 7:23:57 下午 section10.demo1.MainApp main
信息: Woman{name='小丽'age='24'}
4月 08, 2022 7:23:57 下午 section10.demo1.Woman destroy
信息: Bean 正在销毁,关灯睡觉
由运行结果可以看出,postProcessBeforeInitialization()
方法是在 Bean 实例化和属性注入后,自定义初始化方法前执行的。而 postProcessAfterInitialization()
方法是在自定义初始化方法后执行的。由于 getOrder 方法返回值越大,优先级越低,因此 MakeUp(化妆) 先执行,DressUp(打扮) 后执行。