春に一般的に使用されるBeanPostProcessor(オン)

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プロパティの値を設定する前に呼び出されます。通常、構成の属性値を変更または削除するために使用されます
56件の元の記事が公開されました 高く評価しました 14 訪問者20,000以上

おすすめ

転載: blog.csdn.net/Bronze5/article/details/105458285