1.はじめに
BeanPostProcessorは、Beanポストプロセッサとして変換されます。これは、Springがユーザーに提供するインターフェースで、Beanをロードするロジックを拡張します。
春のBeanの読み込みは、大まかに4つのステップに分けられます。Beanの作成、事前のBeanの公開、Beanへの属性の入力、およびBeanの初期メソッドの呼び出しです。
BeanPostProcessorはいくつかのインターフェースメソッドを定義します。Springは、Beanをロードする特定のステップでこれらのメソッドをコールバックして、ユーザー拡張のロジックを実行します。:一般的に構築BeanPostProcessorありInstantiationAware BeanPostProcessor、SmartInstantiationAware BeanPostProcessor、MergedBeanDefinitionポストプロセッサ、以下のような関係がある:
スペースが限られている、私たちだけの章ではBeanPostProcessorと説明InstantiationAware BeanPostProcessor後2つのプロセッサ、SmartInstantiationAwareとMergedBeanDefinitionプロセッサ次の記事分析が。Bean読み込みのどのステップがこれらのBeanPostProcessorsのメソッドを呼び出すかを見てみましょう。
第二に、ソースコードの解釈と検証
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部門クラスの作成
@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アプリケーションの結論:
- postProcessBefore Initialization:Bean初期化メソッドを呼び出す前に呼び出されます
- postProcessAfter Initialization:呼び出しBeanの初期化後に呼び出されます
2. InstantiationAwareBeanPostProcessorは、InstantiationAware
ポストプロセッサを使用して、Beanの作成とBeanの属性の充填プロセスの前に、Beanの読み込みの2つの段階でそれぞれ使用されます。
2.1ソースコード
Beanを作成する前に、InstantationAwareBeanPostProcessorに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をインスタンス化する前に、InstantAwareポストプロセッサーの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メソッドにあります。InstantAwareポストプロセッサーが2か所で呼び出されていることがわかります。1. Beanプロパティを解析する前に、InstantAwareポストプロセッサのpostProcessAfterInstantiationメソッドを呼び出します。2. Beanプロパティを設定する前に、InstantAwareポストプロセッサのpostProcessPropertyValuesメソッドを呼び出します。
フローチャートは次のとおりです
。2.2検証
2.2.1部門クラスの作成(省略、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の実行結果アプリケーションの結論:
- postProcessBefore Instantiation:Beanをインスタンス化する前に呼び出されます
- postProcessAfter Instantiation:Beanをインスタンス化した後、Beanプロパティを解析する前に呼び出されます
- postProcessPropertyValues:設定されたBeanプロパティを解析した後、Beanプロパティの値を設定する前に呼び出されます。通常、構成の属性値を変更または削除するために使用されます