BeanPostProcessor commonly used in spring (on)

1. Introduction

BeanPostProcessor is translated as a bean post processor , which is an interface that Spring provides to users to extend the logic of loading beans.

Loading beans in spring can be roughly divided into four steps: creating a bean, exposing the bean in advance , filling the bean with attributes, and calling the bean's initial method

BeanPostProcessor defines some interface methods. Spring will call back these methods at specific steps of loading beans to execute the logic of user extension. Common built-in BeanPostProcessors are: InstantiationAware BeanPostProcessor, SmartInstantiationAware BeanPostProcessor, MergedBeanDefinition PostProcessor, the relationship diagram is as follows:
Insert picture description herespace is limited, in this chapter we only talk about two postprocessors BeanPostProcessor and InstantiationAware BeanPostProcessor, SmartInstantiationAware and MergedBeanDefinition postprocessor analysis in the next article. Let's take a look at which steps of bean loading will call the methods in these BeanPostProcessors.

Second, source code interpretation and verification

1. Application of
BeanPostProcessor The methods in BeanPostProcessor are mainly used before and after the bean initialization method is called to help users extend the initialization logic.
1.1 Source code

	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;
	}

This code comes from the initializeBean method of the AbstractAutowireCapableBeanFactory class . You can see that applyBeanPostProcessorsBeforeInitialization is called before the bean initialization method is called, and applyBeanPostProcessorsAfterInitialization is called after the bean initialization method is called. Click inside to see

	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;
	}

The flowchart of BeanPostProcessor call is as follows:Insert picture description here

1.2 Verification
1.2.1 Create a Department class

@Data
public class Department {
    private Integer id;
    private String name;

    public void testInitMethod(){
        System.out.println("department初始化方法:testInitMethod");
    }
}

1.2.2 Create a postprocessor that implements 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 Configure bean initialization method

    <!-- 扫描后处理器 -->
    <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 Implementation

    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 Implementation result
Insert picture description here
BeanPostProcessor application conclusion :

  • postProcessBefore Initialization : Called before calling the bean initialization method
  • postProcessAfter Initialization : Called after the initialization of the calling bean

2. InstantiationAwareBeanPostProcessor uses
InstantationAware postprocessor to be used in two stages of bean loading, respectively before bean creation and bean attribute filling process .

2.1 Source Code
Before creating a bean, it will give InstantationAwareBeanPostProcessor a chance to return the bean instance.

	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;
	}

The above code is in the resolveBeforeInstantiation method of AbstractAutowireCapableBeanFactory. Here we should pay attention to the difference between instantiation and initialization , instantiation is to create a bean, initialization is to assign a value to the bean. Spring will call the postProcessBeforeInstantiation method of the InstantAware postprocessor before instantiating the bean.
The specific calling code is as follows:

	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;
	}

Source code for filling properties of beans

	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);
		}
	}

This code can be seen in the populateBean method of the AbstractAutowireCapableBeanFactory class. There are two places where InstantAware postprocessor is called. 1. Call the postProcessAfterInstantiation method of the InstantAware postprocessor before parsing the bean properties. 2. Call the postProcessPropertyValues ​​method of the InstantAware postprocessor before setting the bean properties.
The flow chart is as follows: Insert picture description here
2.2 Verification
2.2.1 Create a Department class (omitted, same as 1.2.1)
2.2.2 Configure 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 Create a postprocessor that implements 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 Executing code

    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 Execution result
Application conclusion of InstantiationAwareBeanPostProcessor :

  • postProcessBefore Instantiation : called before instantiating the bean
  • postProcessAfter Instantiation : called after instantiating the bean, before parsing the bean properties
  • postProcessPropertyValues: After parsing the configured bean properties, it is called before setting values ​​for the bean properties. Generally used to modify or delete the attribute value of the configuration
56 original articles published · Liked 14 · Visitors 20,000+

Guess you like

Origin blog.csdn.net/Bronze5/article/details/105458285