一、介绍
BeanPostProcessor翻译过来叫bean后处理器,是spring提供给用户用来扩展加载bean逻辑的一个接口。
spring中加载bean可以粗略的分为四个步骤:创建bean、提前暴露bean、给bean填充属性、调用bean的初始方法
BeanPostProcessor中定义了一些接口方法,spring会在加载bean的特定步骤回调这些方法,来执行用户扩展的逻辑。常见的内置BeanPostProcessor有:InstantiationAwareBeanPostProcessor、SmartInstantiationAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor,关系图如下:
篇幅有限,本章我们只讲述BeanPostProcessor和InstantiationAwareBeanPostProcessor两个后处理器,SmartInstantiationAware和MergedBeanDefinition后处理器在下一篇文章分析。下面我们来看下bean加载的哪些步骤,会调用到这些BeanPostProcessor中的方法。
二、源码解读与验证
1. BeanPostProcessor的应用
BeanPostProcessor中的方法,主要用在bean初始化方法调用前后,帮助用户扩展初始化逻辑。
1.1 源码
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 1. 应用后处理器的BeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 2. 调用bean的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 3. 调用后处理器的AfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
该代码来自于AbstractAutowireCapableBeanFactory类的initializeBean方法,可以看到在调用bean的初始化方法之前调用了applyBeanPostProcessorsBeforeInitialization,调用bean的初始化方法之后调用了applyBeanPostProcessorsAfterInitialization。点进去看看
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
// 初始化前方法
Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
// 初始化后方法
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
BeanPostProcessor调用流程图如下:
1.2 验证
1.2.1 创建一个Department类
@Data
public class Department {
private Integer id;
private String name;
public void testInitMethod(){
System.out.println("department初始化方法:testInitMethod");
}
}
1.2.2 创建一个实现BeanPostProcessor的后处理器
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("普通后处理器的初始化前方法,beanName:" + beanName + ";bean:" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("普通后处理器的初始化后方法,beanName:" + beanName + ";bean:" + bean);
return bean;
}
}
1.2.3 配置bean的初始化方法
<!-- 扫描后处理器 -->
<context:component-scan base-package="com.kaka.spring.beans.factory.config" />
<!-- 指定department的初始化方法 -->
<bean id="department" class="com.kaka.spring.pojo.Department" init-method="testInitMethod">
<property name="name" value="技术部"/>
</bean>
1.2.4 执行
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Department bean = classPathXmlApplicationContext.getBean("department", Department.class);
System.out.println(bean);
}
1.2.5 执行结果
BeanPostProcessor应用结论:
- postProcessBeforeInitialization:调用bean的初始化方法之前调用
- postProcessAfterInitialization:调用bean的初始化之后调用
2. InstantiationAwareBeanPostProcessor应用
InstantiationAware后处理器在bean加载的两个阶段用到,分别是bean的创建之前和bean属性填充过程中。
2.1 源码
创建bean之前会给InstantiationAwareBeanPostProcessor一个机会,来返回bean实例。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 调用InstantiationAware的实例化前处理方法
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
// 如果有返回值
if (bean != null) {
// 调用普通BeanPostProcessors的初始化后处理方法
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
以上代码在AbstractAutowireCapableBeanFactory的resolveBeforeInstantiation方法中。这里要注意下实例化和初始化的区别,实例化是创建bean,初始化是给bean赋值。spring在实例化bean之前,会调用InstantiationAware后处理器的postProcessBeforeInstantiation方法。
具体调用的代码如下:
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// InstantiationAware的实例化前方法
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
// 如果不返回null,就结束
if (result != null) {
return result;
}
}
}
return null;
}
给bean填充属性的源码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 省略判空的代码...
boolean continueWithPropertyPopulation = true;
// 1. 再给InstantiationAware后处理器一个机会返回bean
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// postProcessAfterInstantiation方法返回false就跳出
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
// 2. postProcessAfterInstantiation方法返回false,就不进行下面的属性填充了
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 省略解析PropertyValues的代码...
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 3. 给bean填充属性前回调该方法
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// 4. 把解析的PropertyValues设置到bean的属性中
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
该代码在AbstractAutowireCapableBeanFactory类的populateBean方法中,可以看到有两处调用了InstantiationAware后处理器。1. 解析bean属性前调用InstantiationAware后处理器的postProcessAfterInstantiation方法。 2. 设置bean属性之前调用InstantiationAware后处理器的postProcessPropertyValues方法。
流程图如下:
2.2 验证
2.2.1 创建一个Department类(省略,同1.2.1)
2.2.2 配置bean
<!-- 扫描后处理器 -->
<context:component-scan base-package="com.kaka.spring.beans.factory.config" />
<!-- 仅配置department的name属性 -->
<bean id="department" class="com.kaka.spring.pojo.Department" init-method="testInitMethod">
<property name="name" value="技术部"/>
</bean>
2.2.3 创建一个实现InstantiationAwareBeanPostProcessor的后处理器
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
/**
* 创建bean之前调用
* 返回值为null,spring会继续根据配置创建bean;否则把该返回值作为bean实例返回
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("创建" + beanName + "前调用,beanName:" + beanName);
return null;
}
/**
* 创建bean之后,解析bean属性之前调用
* 返回值为true则继续解析配置的bean属性,返回false则终止解析配置的bean属性,直接返回此时的bean
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("创建bean之后,解析bean属性之前调用,beanName:" + beanName);
return true;
}
/**
* 解析完成配置的bean属性之后,给bean的属性设置值之前执行
* 可以修改解析后的PropertyValues(一般会在PropertyValues的基础上创建一个MutablePropertyValues)
*/
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
String beanName) throws BeansException {
System.out.println("解析完成配置的bean属性之后,给bean的属性设置值之前执行,beanName:" + beanName);
// 如果是beanName是department
if ("department".equals(beanName)) {
// 从PropertyValues的基础上创建一个MutablePropertyValues
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues(pvs);
// 创建一个PropertyValue,来承载一个属性的配置。同<property />标签的配置
PropertyValue propertyValue = new PropertyValue("id", 2);
// 添加到propertyValueList
mutablePropertyValues.getPropertyValueList().add(propertyValue);
return mutablePropertyValues;
}
return pvs;
}
}
2.2.4 执行代码
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
Department bean = classPathXmlApplicationContext.getBean("department", Department.class);
System.out.println(bean);
}
2.2.5 执行结果
InstantiationAwareBeanPostProcessor应用结论:
- postProcessBeforeInstantiation:实例化bean之前调用
- postProcessAfterInstantiation:实例化bean之后,解析bean属性之前调用
- postProcessPropertyValues:解析配置的bean属性之后,给bean的属性设置值之前调用。一般用来修改或删除配置的属性值