spring bean 擴展點

BeanFactoryPostProcessor

各種Aware

BeanPostProcessor

隱藏的一些特殊功能

下文將一項一項地進行梳理

BeanFactoryPostProcessor

簡介

BeanFactoryPostProcessor是一個很重要的接口,其中只有一個方法

voidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throwsBeansException;

它起作用的時機發生在解析成BeanDefinition后,實例化之前。從名字可以看出來,BeanFactoryPostProcessor針對的應該是容器級別的擴展,名為“BeanFactory PostProcessor”即對容器中所有的BeanDefinition都起普遍作用。BeanFactoryPostProcessor有幾個我們比較常用的子類PropertyPlaceholderConfigurer、CustomEditorConfigurer,前者用于配置文件中的${var}變量替換,后者用于自定義編輯BeanDefinition中的屬性值,合理利用CustomEditorConfigurer會有一些意想不到的效果(例如可以通過修改某些屬性實現類似aop的功能)。

使用

如果是在BeanFactory中使用,我們需要

PropertyPlaceholderConfigurer? configurer = new PropertyPlaceholderConfigurer();configurer.setLaction("xxx");configurer.postProcessBeanFactory(beanFactory);

很繁瑣,很麻煩,而且通常我們并不喜歡硬編碼直接使用BeanFactory。在ApplicationContext中得到了改善,使用BeanFactoryPostProcessor只需要在xml文件中進行相應的配置就行,因為ApplicationContext在初始化過程中會調用invokeBeanFactoryPostProcessors(beanFactory),該函數會找出所有BeanFactoryPostProcessor類型的bean,調用postProcessBeanFactory方法。

BeanPostProcessor

簡介

BeanPostProcessor很容易和BeanFactoryPostProcessor混淆,但從名字上來說,BeanPostProcessor是“Bean PostProcessor”,主要針對于Bean這一級別,關注的主要是Bean實例化后,初始化前后的。為什么說主要呢?因為存在特例,有一個BeanPostProcessor的調用并不是發生在實例化后,初始化前后。BeanPostProcessor接口存在兩個方法,從名字可以看粗一個調用在初始化之前,一個調用在初始化之后。

ObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException;ObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException;

BeanPostProcessor在BeanFactory的初始化bean的函數initializeBean中,主要代碼為,基本就是取出所有的BeanPostProcessor,然后遍歷調用其postProcessBeforeInitialization或者postProcessAfterInitialization方法。

if(mbd ==null|| !mbd.isSynthetic()) {? ? ? ? ? ? wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);? ? ? ? }try{? ? ? ? ? ? invokeInitMethods(beanName, wrappedBean, mbd);? ? ? ? }catch(Throwable ex) {thrownewBeanCreationException(? ? ? ? ? ? ? ? ? ? (mbd !=null? mbd.getResourceDescription() :null),? ? ? ? ? ? ? ? ? ? beanName,"Invocation of init method failed", ex);? ? ? ? }if(mbd ==null|| !mbd.isSynthetic()) {? ? ? ? ? ? wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);? ? ? ? }publicObjectapplyBeanPostProcessorsBeforeInitialization(ObjectexistingBean,StringbeanName)throwsBeansException {Objectresult = existingBean;for(BeanPostProcessor beanProcessor : getBeanPostProcessors()) {? ? ? ? ? ? result = beanProcessor.postProcessBeforeInitialization(result, beanName);if(result ==null) {returnresult;? ? ? ? ? ? }? ? ? ? }returnresult;? ? }

使用

Spring利用BeanPostProcessor給了我們在bean初始化前后“doSomething”的機會。

在BeanFactory中使用需要編碼

beanFactory.addBeanPostProcessor(newSomeBeanPostProcessor);

但是在ApplicationContext中,我們只需要將自定義的BeanPostProcessor配置到xml文件中即可。ApplicationContext在初始化過程中會識別所有的BeanPostProcessors并添加到BeanFactory中。

各種Aware

簡介

這種類型的擴展點是我們比較熟悉的了,例如ApplicationContextAware、BeanFactoryAware等,Aware的接口用于標識“我需要這個對象”,例如ApplicationContextAware通知容器我需要“當前的ApplicationContext對象”。這個Spring給我們提供的一種用于獲取有用對象的一種好的方式。

使用

需要注意的是,Aware起作用的時機是在Bean已經完成實例化之后,初始化Bean的同時。而且需要注意的是BeanFactory對于Aware的處理和ApplicationContext是不同的。

先看BeanFactory中的處理方式,各種Aware被調用的地方是在初始化bean的函數

initializeBean中

protectedObjectinitializeBean(finalStringbeanName,finalObjectbean, RootBeanDefinition mbd) {if(System.getSecurityManager() !=null) {? ? ? ? ? ? AccessController.doPrivileged(newPrivilegedAction() {publicObjectrun() {? ? ? ? ? ? ? ? ? ? invokeAwareMethods(beanName, bean);returnnull;? ? ? ? ? ? ? ? }? ? ? ? ? ? }, getAccessControlContext());? ? ? ? }else{? ? ? ? ? ? invokeAwareMethods(beanName, bean);? ? ? ? }ObjectwrappedBean = bean;if(mbd ==null|| !mbd.isSynthetic()) {? ? ? ? ? ? wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);? ? ? ? }try{? ? ? ? ? ? invokeInitMethods(beanName, wrappedBean, mbd);? ? ? ? }catch(Throwable ex) {thrownewBeanCreationException(? ? ? ? ? ? ? ? ? ? (mbd !=null? mbd.getResourceDescription() :null),? ? ? ? ? ? ? ? ? ? beanName,"Invocation of init method failed", ex);? ? ? ? }if(mbd ==null|| !mbd.isSynthetic()) {? ? ? ? ? ? wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);? ? ? ? }returnwrappedBean;? ? }privatevoidinvokeAwareMethods(finalStringbeanName,finalObjectbean) {if(beaninstanceofAware) {if(beaninstanceofBeanNameAware) {? ? ? ? ? ? ? ? ((BeanNameAware) bean).setBeanName(beanName);? ? ? ? ? ? }if(beaninstanceofBeanClassLoaderAware) {? ? ? ? ? ? ? ? ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());? ? ? ? ? ? }if(beaninstanceofBeanFactoryAware) {? ? ? ? ? ? ? ? ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);? ? ? ? ? ? }? ? ? ? }? ? }

可以看到其發生在invokeInitMethods之前。而ApplicationContext怎么處理呢?ApplicationContext本身是利用BeanFactory進行容器的初始化,而BeanFactory卻硬編碼了invokeAwareMethods中Aware的類型,那ApplicationContext究竟是怎么調用ApplicationContextAware的呢,答案就在函數prepareBeanFactory中,

beanFactory.addBeanPostProcessor(newApplicationContextAwareProcessor(this));

ApplicationContext為beanFactory增加了ApplicationContextAwareProcessor,ApplicationContextAwareProcessor是一種BeanPostProcessor。前文提到BeanPostProcessor發生在bean初始化前后,在bean初始化之前將調用postProcessBeforeInitialization方法,ApplicationContextAwareProcessor#postProcessBeforeInitialization如下:

publicObjectpostProcessBeforeInitialization(finalObjectbean,StringbeanName)throwsBeansException {? ? ? ? AccessControlContext acc =null;if(System.getSecurityManager() !=null&&? ? ? ? ? ? ? ? (beaninstanceofEnvironmentAware || beaninstanceofEmbeddedValueResolverAware ||? ? ? ? ? ? ? ? ? ? ? ? beaninstanceofResourceLoaderAware || beaninstanceofApplicationEventPublisherAware ||? ? ? ? ? ? ? ? ? ? ? ? beaninstanceofMessageSourceAware || beaninstanceofApplicationContextAware)) {? ? ? ? ? ? acc =this.applicationContext.getBeanFactory().getAccessControlContext();? ? ? ? }if(acc !=null) {? ? ? ? ? ? AccessController.doPrivileged(newPrivilegedAction() {publicObjectrun() {? ? ? ? ? ? ? ? ? ? invokeAwareInterfaces(bean);returnnull;? ? ? ? ? ? ? ? }? ? ? ? ? ? }, acc);? ? ? ? }else{? ? ? ? ? ? invokeAwareInterfaces(bean);? ? ? ? }returnbean;? ? }privatevoidinvokeAwareInterfaces(Objectbean) {if(beaninstanceofAware) {if(beaninstanceofEnvironmentAware) {? ? ? ? ? ? ? ? ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());? ? ? ? ? ? }if(beaninstanceofEmbeddedValueResolverAware) {? ? ? ? ? ? ? ? ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(newEmbeddedValueResolver(this.applicationContext.getBeanFactory()));? ? ? ? ? ? }if(beaninstanceofResourceLoaderAware) {? ? ? ? ? ? ? ? ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);? ? ? ? ? ? }if(beaninstanceofApplicationEventPublisherAware) {? ? ? ? ? ? ? ? ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);? ? ? ? ? ? }if(beaninstanceofMessageSourceAware) {? ? ? ? ? ? ? ? ((MessageSourceAware) bean).setMessageSource(this.applicationContext);? ? ? ? ? ? }if(beaninstanceofApplicationContextAware) {? ? ? ? ? ? ? ? ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);? ? ? ? ? ? }? ? ? ? }? ? }

可以看出ApplicationContext利用ApplicationContextAwareProcessor完成了ApplicationContext中特有的一些Aware的調用,發生的時機在初bean始化之前。

一種特殊的BeanPostProcessor-InstantiationAwareBeanPostProcessor

前文提到BeanPostProcessor主要作用于Bean實例化后,初始化前后,但是存在特例,InstantiationAwareBeanPostProcessor就是特例,其發生在Bean實例化前,

在真正調用doCreate()創建bean實例化之前,調用了resolveBeforeInstantiation進行了短路操作,如果此方法返回值不為空則直接返回bean。spring注釋“Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. ”給BeanPostProcessors一個機會返回代理proxy對象。

try{? // GiveBeanPostProcessorsa chance to return a proxy instead of the targetbeaninstance.? Objectbean= resolveBeforeInstantiation(beanName,mbd);if(bean!= null) {? ? ? returnbean;}}? ? protected Object resolveBeforeInstantiation(StringbeanName,RootBeanDefinition mbd) {? ? ? ? Objectbean= null;if(!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)){? ? ? ? ? ? // Make surebeanclass is actually resolved at this point.if(mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {bean= applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(),beanName);if(bean!= null) {bean= applyBeanPostProcessorsAfterInitialization(bean,beanName);}? ? ? ? ? ? }? ? ? ? ? ? mbd.beforeInstantiationResolved= (bean!= null);}? ? ? ? returnbean;}

我們熟知的AOP,對target對象進行代理就是實現了InstantiationAwareBeanPostProcessor接口,在Bean實例化之前短路操作返回代理Proxy對象。

ApplicationContext的事件發布

--待續

總結

本文總結了Spring容器中幾種使用較多的擴展機制,Spring作為一個設計良好的框架,遵循了“對修改封閉,對擴展開放”的原則,我們可以根據自己的實際需要來自定義BeanFactoryPostProcessor,BeanPostProcessor來在bean的生命周期里doSomething,實現各種Aware接口拿到容器中提供的一些有用對象,通過自定義監聽器監聽容器的事件等。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容