Spring源碼分析衍生篇四:後處理器 BeanPostProcessor

一、前言

本文是 Spring源碼分析:單例bean的獲取 - createBean 的衍生文章。主要是因爲本人菜雞,在分析源碼的過程中還有一些其他的內容不理解,故開設衍生篇來完善內容以學習。

二、BeanPostProcessor

所謂的 BeanPostProcessor 翻譯過來就是Bean後處理器。實際上Spring還有一類後處理器BeanFactoryPostProcessor,源碼還沒看到這,暫不分析。

1. 什麼是 BeanPostProcessor

BeanPostProcessor 是 Spring提供給我們的一個非常重要的擴展接口,並且Spring內部的很多功能也是通過 BeanPostProcessor 來完成的(目前看到最典型的就是 AnnotationAwareAspectJAutoProxyCreator 的 注入)。

2. BeanPostProcessor 的種類

BeanPostProcessor 在Spring 中的子類非常多(idea 顯是有46個),比如

  • InstantiationAwareBeanPostProcessorAdapter : 在Spring 的bean加載過程中起了非常重要的作用
  • AnnotationAwareAspectJAutoProxyCreator : bean 創建過程中的 屬性注入時起作用
  • AspectJAwareAdvisorAutoProxyCreator : Aspect 的 AOP 功能實現也全仰仗BeanPostProcessor 的特性。

3. BeanPostProcessor 的註冊

BeanPostProcessor 的註冊是在 AbstractApplicationContext#registerBeanPostProcessors 中完成的。在Spring 剛剛啓動時候,會調用refresh() 方法,隨機調用registerBeanPostProcessors 方法。 在這個方法中,Spring 將各處的BeanPostProcessor 的實現類 註冊到 BeanFactory.beanPostProcessors 屬性中,後面獲取BeanPostProcessor 時直接通過該屬性獲取。

三、基本介紹

日常使用中,我們一般編寫一個類來實現 BeanPostProcessor 或者 InstantiationAwareBeanPostProcessor 接口,根據每個方法的調用時機,來完成響應的工作。
下面介紹一下接口方法,這裏通過 InstantiationAwareBeanPostProcessor 接口來介紹 。InstantiationAwareBeanPostProcessorBeanPostProcessor 的子接口,在 BeanPostProcessor 基礎上又擴展了三個方法。

@Component
public class DemoPostProcesser implements InstantiationAwareBeanPostProcessor {

    //InstantiationAwareBeanPostProcessor 提供的方法, 在 Class<T> -> T 的轉換過程中
    // 此時bean還沒創建,可以通過這方法代替 Spring 容器創建的方法
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("DemoPostProcesser.postProcessBeforeInstantiation   ###  1");
        return null;
    }

    //InstantiationAwareBeanPostProcessor 提供的方法, 返回的值代表是否需要繼續注入屬性,
    // 如果返回true,則會調用postProcessProperties和postProcessPropertyValues 來注入屬性
    // 此時bean已經創建,屬性尚未注入
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("DemoPostProcesser.postProcessAfterInstantiation   ###  2");
        return true;
    }
    //InstantiationAwareBeanPostProcessor 提供的方法,可以在這個方法中進行bean屬性的注入,Aop 就是在此方法中進行了代理的創建
    // 只有postProcessAfterInstantiation 返回true 時纔會調用
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        System.out.println("DemoPostProcesser.postProcessProperties   ###  3");
        return pvs;
    }
    //InstantiationAwareBeanPostProcessor 提供的方法,可以在這個方法中進行bean屬性的注入, 這個方法已經過時,使用postProcessProperties 代理
    // 只有postProcessAfterInstantiation 返回true 時 且 postProcessProperties 返回 null 時調用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        System.out.println("DemoPostProcesser.postProcessPropertyValues   ###  4");
        return pvs;
    }

    // BeanPostProcessor 提供的方法,在bean初始化前調用,這時候的bean大體已經創建完成了,在完成一些其他屬性的注入
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("DemoPostProcesser.postProcessBeforeInitialization   ###  5");
        return bean;
    }
    // BeanPostProcessor 提供的方法,在bean初始化後調用,這時候的bean 已經創建完成了
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("DemoPostProcesser.postProcessAfterInitialization   ###  6");
        return bean;
    }
}

其調用順序也和標註相同
在這裏插入圖片描述
注意:

這裏可以看到 postProcessPropertyValues 方法並沒有調用,因爲對於一個 過時的方法 沒必要必須要調用它,前面也提到 postProcessAfterInstantiation 返回true 並且 postProcessProperties 返回不爲null 纔會調用該方法,這裏postProcessProperties 返回不爲null ,所以不會調用postProcessPropertyValues 方法


四、源碼中的調用場景

下面爲了方便描述,進行一些簡化寫法,爲了後面描述方便

BP : BeanPostProcessor
IBP : InstantiationAwareBeanPostProcessor
SBP : SmartInstantiationAwareBeanPostProcessor


其結構如下圖:
在這裏插入圖片描述


這裏就不具體貼出多少代碼。簡單解釋一下調用場景

Spring 在啓動過程中,會將所有實現了 BeanPostProcessor 接口的子類保存到 AbstractBeanFactory 中的 beanPostProcessors 集合中,如下:

private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

在適當的時候(這個適當的時候就根據 每個接口方法定義的意義來判斷), Spring會獲取 所有的BeanPostProcessor 子類集合,即 beanPostProcessors ,經過類型過濾後,調用對應的方法。比如,就是對 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 方法的調用流程(其餘方法的調用也類似):

	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
		// 因爲只有 InstantiationAwareBeanPostProcessor  類型纔有postProcessBeforeInstantiation 方法,所以這裏要判斷一下是不是 InstantiationAwareBeanPostProcessor   類型
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

1. InstantiationAwareBeanPostProcessor

下面來介紹在 Spring 創建流程中 每個方法的實際調用位置:

1.1. IBP.postProcessBeforeInstantiation

IBP.postProcessBeforeInstantiation 方法在 Bean 創建 之前調用,我所理解的目的是替換Spring 容器創建bean, 當 IBP.postProcessBeforeInstantiation 返回不爲null時,則不會再通過Spring 創建bean,而是使用 IBP.postProcessBeforeInstantiation 返回的bean。

			...
			// 該方法中 調用了postProcessBeforeInstantiation 方法,並且可能調用 postProcessAfterInitialization 方法
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
			...
			// 真正去創建bean
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			...

resolveBeforeInstantiation 方法內容如下,可以看到 當 applyBeanPostProcessorsBeforeInstantiation 方法(applyBeanPostProcessorsBeforeInstantiation 調用了 postProcessBeforeInstantiation 方法) 返回值不爲 null,則會調用 postProcessAfterInstantiation 方法。因爲這裏bean返回不爲null,則代表bean創建成功了,就會調用創建成功後的方法,即 postProcessAfterInstantiation

	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) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

這裏需要注意,在 resolveBeforeInstantiation 方法中,當 bean != null 時 調用了 applyBeanPostProcessorsAfterInitialization 方法,即 BP.postProcessAfterInitialization 方法。這是因爲如果 bean != null, 則說明 bean 的創建已經完成,那麼這裏則是最後調用bean 的後置處理的機會,即調用BP.postProcessAfterInitialization 方法的最後機會。

1.2. IBP.postProcessAfterInstantiation & IBP.postProcessProperties & IBP.postProcessPropertyValues

IBP.postProcessAfterInstantiationIBP.postProcessPropertiesIBP.postProcessPropertyValues 的調用場景只有一處,在AbstractAutowireCapableBeanFactory#populateBean 方法中,此時bean已經創建完成,正在進行屬性注入。而 IBP.postProcessAfterInstantiation 的返回值決定是否繼續注入

大致代碼如下

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		...
		// 調用 postProcessAfterInstantiation 方法嗎,如果返回false,直接return;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
		}

		... 
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					// 調用 postProcessProperties 注入屬性
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						// 調用 postProcessPropertyValues 注入屬性
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
	...
	}

通過代碼我們可以比較清楚的看到整體邏輯:

  1. IBP.postProcessAfterInstantiation 返回true,纔會執行下面步驟
  2. 調用 IBP.postProcessProperties 注入屬性,
  3. IBP.postProcessProperties 返回爲null,纔會執行下面步驟
  4. 調用 IBP.postProcessPropertyValues 注入屬性

2. BeanPostProcessor

2.1. BP.postProcessBeforeInitialization

BP.postProcessBeforeInitialization 調用時機是bean已經創建完成,但是尚未初始化,即一些屬性配置尚未完成(我看到的就一個 init-method 的配置)。使用場景也只有一處,即
AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)

程序走到這裏,代表 resolveBeforeInstantiation 方法 中的 IBP.postProcessBeforeInstantiation 並未代理 bean的創建,在這裏則是由Spring 創建的bean的時候來調用。

代碼如下,

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		....
		// 調用 BP.postProcessBeforeInitialization
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		// 初始化屬性,貌似就初始化了 一個 init-method
		...
		if (mbd == null || !mbd.isSynthetic()) {
			// 調用 BP.postProcessAfterInitialization
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

2.2. BP.postProcessAfterInitialization

IBP.postProcessAfterInstantiation 的調用都被封裝到 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization 方法中。
applyBeanPostProcessorsAfterInitialization 方法的調用

applyBeanPostProcessorsAfterInitialization 方法在下面三個方法中調用:

  • AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
  • AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)
  • AbstractAutowireCapableBeanFactory#postProcessObjectFromFactoryBean

2.2.1 resolveBeforeInstantiation

resolveBeforeInstantiation 方法的調用有如下三處

  • AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[]) 這裏的調用實際上就是上面講的 IBP.postProcessBeforeInstantiation 的調用後續,所以這裏不再重複

  • AbstractAutowireCapableBeanFactory#getSingletonFactoryBeanForTypeCheck

  • AbstractAutowireCapableBeanFactory#getNonSingletonFactoryBeanForTypeCheck


2.2.2 initializeBean

上面介紹 BP.postProcessBeforeInitialization 的時候已經說了,所以這裏不再贅述


2.2.3 postProcessObjectFromFactoryBean

FactoryBeanRegistrySupport#getObjectFromFactoryBean 中調用,在從 FactoryBean 中獲取 bean時調用,在此調用可以替換掉 FactoryBean 中的返回的bean。


3. SmartInstantiationAwareBeanPostProcessor

SmartInstantiationAwareBeanPostProcessor 在 IBP 之上又擴展了三個方法,不過我們一般不會使用,所以這裏簡單敘述一下SmartInstantiationAwareBeanPostProcessor 三個方法的作用

  • Class<?> predictBeanType(Class<?> beanClass, String beanName) : 在進行bean類型匹配時調用,返回值和期望值進行匹配。

  • Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) : 在 Spring 加載bean 的時候,判斷是否需要通過構造注入時,如果返回的值不爲空,則進行有參構造注入。

    	// determineConstructorsFromBeanPostProcessors 中調用了  determineCandidateConstructors 方法,如果ctors != null, 則進行有參構造autowireConstructor
    		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
    				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    			return autowireConstructor(beanName, mbd, ctors, args);
    		}
    
  • Object getEarlyBeanReference(Object bean, String beanName) : 在 Spring 解決循環依賴時候使用,返回的值將作爲ObjectFactory 的 保存的Object,用於循環依賴的提前暴露。

    		if (earlySingletonExposure) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Eagerly caching bean '" + beanName +
    						"' to allow for resolving potential circular references");
    			}
    			// getEarlyBeanReference 的返回值作爲 ObjectFactory 的返回值保存到singletonFactories緩存中
    			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    		}
    

最後,附一張自己畫的調用流程圖,由於完全有本人自己閱讀繪製,可能會出現些許紕漏,如果發現,麻煩指正,謝謝。
在這裏插入圖片描述


以上:內容部分參考
《Spring源碼深度解析》
如有侵擾,聯繫刪除。 內容僅用於自我記錄學習使用。如有錯誤,歡迎指正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章