spring中常用的BeanPostProcessor(上)

一、介绍

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的属性设置值之前调用。一般用来修改或删除配置的属性值
发布了56 篇原创文章 · 获赞 14 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Bronze5/article/details/105458285
今日推荐