BeanPostProcessor和BeanFactoryPostProcessor族類原理及使用

1. 作用及區(qū)別

Spring+IOC容器源碼分析 一文中的分析中,貫穿整個(gè)過(guò)程主線的大概是這樣一條路線:

  • 加載Bean定義信息
  • 處理加載的Bean定義信息
  • 從Bean定義創(chuàng)建Bean實(shí)例
  • Bean創(chuàng)建的后置處理(屬性填充、初始化回調(diào)等等)

當(dāng)然這其中還有相當(dāng)多的實(shí)現(xiàn)細(xì)節(jié),包括 容器加載前的準(zhǔn)備、Bean容器的準(zhǔn)備等等。

這篇文章要說(shuō)的是Spring框架中兩個(gè)相當(dāng)重要的類族:BeanFactoryPostProcessorBeanPostProcessor

其應(yīng)用的位置對(duì)應(yīng)于上面的過(guò)程2和4,也就是:

  • BeanFactoryPostProcessor:在實(shí)例化之前,整合 BeanDefinition 的過(guò)程中調(diào)用;操作對(duì)象為Bean定義
  • BeanPostProcessor:在BeanDefinition注冊(cè)完成之后進(jìn)行注冊(cè),在創(chuàng)建Bean過(guò)程中的實(shí)例化前后分別調(diào)用其中定義的方法;其操作對(duì)象為:已經(jīng)實(shí)例化且進(jìn)行了屬性填充待初始化的Bean實(shí)例

注意要區(qū)分這兩個(gè)類的作用以及調(diào)用時(shí)間和作用對(duì)象都是不同的

2. 常見(jiàn)的實(shí)現(xiàn)類解析

下面這些實(shí)現(xiàn)類都是在分析SpringIOC源碼時(shí)提到過(guò)的,在這里我們?cè)僭敿?xì)的看一下他們的作用以及調(diào)用事件

本文中提到的所有這些實(shí)現(xiàn)類都是在SpringIOC源碼分析中提到過(guò)的,其在源碼中具體的使用位置可以查看 SpringIOC源碼分析 等三篇文章

2.1 BeanFactoryPostProcessor 的常見(jiàn)實(shí)現(xiàn)類

2.1.2 BeanDefinitionRegistryPostProcessor:

  1. 官方注解:對(duì)標(biāo)準(zhǔn) BeanFactoryPostProcessor SPI的擴(kuò)展,允許在常規(guī)BeanFactoryPostProcessor檢測(cè)啟動(dòng)之前注冊(cè)進(jìn)一步的bean定義。特別地,BeanDefinitionRegistryPostProcessor可以注冊(cè)更多的bean定義,這些定義反過(guò)來(lái)定義BeanFactoryPostProcessor實(shí)例

也就是說(shuō)首先作為一個(gè) BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor 也可以對(duì)應(yīng)用程序上下文的內(nèi)部Bean工廠進(jìn)行其初始化后的修改,也就是可以允許修改Bean定義,例如重寫(xiě)或者添加Bean屬性
另外的,作為 BeanDefinitionRegistryPostProcessor 自身這樣一個(gè)特殊的 BeanFactoryPostProcessor來(lái)講,其接口中的方法允許自定義的去添加更多的Bean定義,例如在這里去添加更多的 BeanFactoryPostProcessor 實(shí)例

總結(jié)一下:BeanFactoryPostProcessor可以修改各個(gè)注冊(cè)的Bean,BeanDefinitionRegistryPostProcessor則可以動(dòng)態(tài)的注冊(cè)Bean到容器中

  1. 使用:BeanDefinitionRegistryPostProcessor 在Spring源碼中的使用主要是在這塊:invokeBeanFactoryPostProcessors(),具體的調(diào)用過(guò)程分析可以查看 Spring+IOC容器源碼分析 文中關(guān)于 invokeBeanFactoryPostProcessors的總結(jié)

2.1.1 ConfigurationClassPostProcessor

  1. ConfigurationClassPostProcessor 是 BeanDefinitionRegistryPostProcessor 的實(shí)現(xiàn)類,是用于對(duì)Configuration類的引導(dǎo)處理的BeanFactoryPostProcessor的擴(kuò)展

在當(dāng)下基于springBoot注解開(kāi)發(fā)應(yīng)用已經(jīng)相當(dāng)廣泛的情況下,可以說(shuō)這個(gè)后置處理器是整個(gè) spring中最最核心的處理器也不為過(guò)。
不同于xml方式通過(guò)解析xml文件獲取到所有Bean定義并將其注冊(cè)到相應(yīng)的緩存,基于注解配置后將所有Bean配置解析成BeanDefinition都是由這個(gè)處理器來(lái)完成的。例如我們常見(jiàn)的:@controller,@service,@mapper,@component,@configuration以及@Import等等

2.調(diào)用時(shí)機(jī)以及作用:

首先 ConfigurationClassPostProcessor 實(shí)現(xiàn)了 BeanDefinitionRegistryPostProcessorPriorityOrdered接口,那么從我們?cè)谥暗奈恼聦?duì)BeanFactoryPostProcess調(diào)用的方法 invokeBeanFactoryPostProcessors()的分析中:
ConfigurationClassPostProcessor 也是在這里進(jìn)行調(diào)用的.通過(guò)其實(shí)現(xiàn)類,主要是調(diào)用其實(shí)現(xiàn)的兩個(gè)方法:

  • postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry):

    解析了加了Configuration注解的類,同時(shí)解析出 @ComponentScan 和 @ComponentScans 掃描出的Bean,也會(huì)解析出加了 @Bean 注解的方法所注冊(cè)的Bean,以及通過(guò) @Import 注解注冊(cè)的Bean和 @ImportResource 注解導(dǎo)入的配置文件中配置的Bean。最終將其加載到BeanDefinition的配置中

  • postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory):

    利用CGLIB對(duì)加了@Configuration注解的類創(chuàng)建動(dòng)態(tài)代理,進(jìn)行增強(qiáng)。最后還會(huì)向spring容器中添加一個(gè)Bean后置處理器:ImportAwareBeanPostProcessor:用來(lái)設(shè)置@Import注解元數(shù)據(jù)

2.2 BeanPostProcessor的常見(jiàn)實(shí)現(xiàn)類

2.2.1 ApplicationContextAwareProcessor

顧名思義,ApplicationContextAwareProcessorBeanPostProcessor對(duì)應(yīng)用上下文中的aware類的處理器擴(kuò)展

首先了解下Spring中的aware類,aware意為"可感知的",在spring中主要是用來(lái)提供對(duì)某種容器級(jí)的Bean的便捷的獲取和連接方式
例如:一般在我們的項(xiàng)目里邊會(huì)有一個(gè)用來(lái)直接獲取Bean的工具類,那么在這里就必須要拿到當(dāng)前存放Bean的BeanFactory,有很多方式獲取到.

  1. 實(shí)現(xiàn)BeanFactoryAware接口,調(diào)用setBeanFactory(BeanFactory beanFactory)將beanFactory賦值給本地beanFactory即可
  2. 實(shí)現(xiàn)ApplicationContextAware接口,調(diào)用setApplicationContext(ApplicationContext applicationContext)從applicationContext中獲取到beanFactory賦值給本地beanFactory
  3. 實(shí)現(xiàn)BeanFactoryPostProcessor,拿到BeanFactory.(這里用BeanFactoryPostProcessor有點(diǎn)殺雞用牛刀的感覺(jué),本來(lái)是用來(lái)做BeanDefinition修改的,這里只是使用了其容器的引用)
  4. 直接注入BeanFactory,再使用自定義的初始化將其賦值到本地

從IOC源碼分析中,我們知道其實(shí)最終創(chuàng)建的BeanFactory是一個(gè)DefaultListableBeanFactory,因此在1、2中的BeanFactory可以直接強(qiáng)轉(zhuǎn)為DefaultListableBeanFactory,以此可以調(diào)用更多詳細(xì)的獲取Bean的方法

扯遠(yuǎn)了,想一個(gè)問(wèn)題,無(wú)論是我們從aware接口獲取值,還是直接注入值,這些aware接口是什么時(shí)候拿到這些引用的呢?這也就是這個(gè)processor的作用

Spring+IOC容器源碼分析 一文中準(zhǔn)備Bean容器的部分:
prepareBeanFactory(factory)中看到了在這里創(chuàng)建了一個(gè)ApplicationContextAwareProcessor并傳入了當(dāng)前上下文引用作為其構(gòu)造參數(shù)
查看源碼我們發(fā)現(xiàn):

  • 它只實(shí)現(xiàn)了 BeanPostProcessor 的 postProcessBeforeInitialization()方法,并在其中對(duì)所有的aware類進(jìn)行了值的設(shè)置,因此我們才能在其它類中通過(guò)這些aware拿到需要的實(shí)例引用;可以看到此處傳入的context類型為ConfigurableApplicationContext
  • 調(diào)用時(shí)機(jī):同BeanPostProcessor的調(diào)用時(shí)機(jī): 屬性填充后,真正實(shí)例化之前實(shí)例化

2.2.2 InstantiationAwareBeanPostProcessor 實(shí)例化可感知的BeanPostProcessor

該類相比較與父接口自定義了三個(gè)方法,這三個(gè)方法都是與bean的實(shí)例化相關(guān)的,這也印證了該類型名稱:InstantiationAware

  1. 主要作用:對(duì)目標(biāo)對(duì)象的實(shí)例化過(guò)程中需要處理的事情,包括實(shí)例化對(duì)象的前后過(guò)程以及實(shí)例的屬性設(shè)置
  2. InstantiationAwareBeanPostProcessor 接口方法的執(zhí)行順序:
  • InstantiationAwareBeanPostProcessor接口中的postProcessBeforeInstantiation,在實(shí)例化之前調(diào)用

    此時(shí)對(duì)象尚未實(shí)例化,因此可以使用這個(gè)方法的返回值來(lái)代替原本該生成的目標(biāo)對(duì)象的實(shí)例(比如代理對(duì)象)

    如果該方法的返回值代替原本該生成的目標(biāo)對(duì)象,后續(xù)只有postProcessAfterInitialization方法會(huì)調(diào)用,其它方法不再調(diào)用;否則按照正常的流程走

  • Bean的實(shí)例化,調(diào)用構(gòu)造方法

  • InstantiationAwareBeanPostProcessor接口中的postProcessAfterInstantiation,在實(shí)例化之后調(diào)用

    此時(shí)對(duì)象已被實(shí)例化,但是該實(shí)例的屬性還未被設(shè)置,都是null
    該方法的返回值是決定要不要調(diào)用postProcessPropertyValues方法的其中一個(gè)因素(因?yàn)檫€有一個(gè)因素是mbd.getDependencyCheck());如果該方法返回false,并且不需要check,那么postProcessPropertyValues就會(huì)被忽略不執(zhí)行;如果返回true, postProcessPropertyValues就會(huì)被執(zhí)行

  • InstantiationAwareBeanPostProcessor接口中的postProcessPropertyValues[當(dāng)postProcessAfterInstantiation返回true才執(zhí)行]

    對(duì)屬性值進(jìn)行修改(這個(gè)時(shí)候?qū)傩灾颠€未被設(shè)置)

  • BeanPostProcessor接口中的postProcessBeforeInitialization,在初始化之前調(diào)用

  • InitializingBean中的afterProperties方法,執(zhí)行初始化

  • BeanPostProcessor接口中的postProcessAfterInitialization,在實(shí)例化之后調(diào)用

    1. 從SpringIOC源碼分析看該類的使用:
1. createBean--resolveBeforeInstantiation--applyBeanPostProcessorsBeforeInstantiation
2. populateBean
  • 在位置1處通過(guò)分析源碼我們知道在這里調(diào)用了 postProcessBeforeInstantiation方法,用來(lái)在這里提前返回生成的對(duì)象實(shí)例,并直接執(zhí)行 postProcessAfterInitialization方法
  • 在位置2處查看源碼又有兩處涉及到該類: 即對(duì)于上述中的其他兩個(gè)方法的調(diào)用,執(zhí)行postProcessAfterInstantiation并根據(jù)其返回值條件判斷是否需要調(diào)用 postProcessPropertyValues 對(duì)對(duì)象進(jìn)行屬性修改

2.2.3 SmartInstantiationAwareBeanPostProcessor 循環(huán)引用獲取早期引用

  1. InstantiationAwareBeanPostProcessor接口的擴(kuò)展,添加了一個(gè)用于預(yù)測(cè)已處理bean的最終類型的回調(diào).

  2. 方法分析:

    • Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException;

    預(yù)測(cè)Bean的類型,返回第一個(gè)預(yù)測(cè)成功的Class類型,如果不能預(yù)測(cè)返回null

    • Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException;

    選擇合適的構(gòu)造器,比如目標(biāo)對(duì)象有多個(gè)構(gòu)造器,在這里可以進(jìn)行一些定制化,選擇合適的構(gòu)造器.beanClass參數(shù)表示目標(biāo)實(shí)例的類型,beanName是目標(biāo)實(shí)例在Spring容器中的name
    返回值是個(gè)構(gòu)造器數(shù)組,如果返回null,會(huì)執(zhí)行下一個(gè)PostProcessor的determineCandidateConstructors方法;否則選取該P(yáng)ostProcessor選擇的構(gòu)造器
    具體的使用:如AutowiredAnnotationBeanPostProcessor實(shí)現(xiàn)將自動(dòng)掃描通過(guò)@Autowired/@Value注解的構(gòu)造器從而可以完成構(gòu)造器注入

    • Object getEarlyBeanReference(Object bean, String beanName) throws BeansException;

    獲得提前暴露的bean引用。主要用于解決循環(huán)引用的問(wèn)題;只有單例對(duì)象才會(huì)調(diào)用此方法

2.2.4 MergedBeanDefinitionPostProcessor:合并Bean定義的PostProcessor

  1. 運(yùn)行時(shí)對(duì)合并的bean定義的后處理器回調(diào)接口。BeanPostProcessor的子接口實(shí)現(xiàn),以便對(duì)Spring BeanFactory用于創(chuàng)建bean實(shí)例的合并bean定義(原始bean定義的已處理副本)進(jìn)行后處理。

例如,{@link#postprocessemergedbeandefinition}方法可以內(nèi)省bean定義,以便在對(duì)bean的實(shí)際實(shí)例進(jìn)行后處理之前準(zhǔn)備一些緩存的元數(shù)據(jù)。它還允許修改bean定義,但僅限于實(shí)際用于并發(fā)修改的定義屬性。本質(zhì)上,這只適用于在{@link RootBeanDefinition}本身上定義的操作,而不適用于其基類的屬性

  • void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

    后置處理對(duì)指定Bean的給定的合并Bean定義

  • default void resetBeanDefinition(String beanName) {}

    通知指定名稱的bean定義已重置,此后處理器應(yīng)清除受影響bean的所有元數(shù)據(jù)

  1. 使用的位置:doCreateBean()

2.2.5 AutowiredAnnotationBeanPostProcessor

BeanPostProcessor的實(shí)現(xiàn),自動(dòng)連接帶注釋的字段、setter方法和任意配置方法。要注入的這些成員是通過(guò)注釋檢測(cè)到的:默認(rèn)情況下,處理Spring的@Autowired和@Value注釋
簡(jiǎn)單來(lái)說(shuō)就是與Spring的autoWired自動(dòng)注入相關(guān)的一個(gè)BeanPostProcessor,我們之所以能方便的使用@Autowired注入其他Bean都要?dú)w功于這個(gè)注解

關(guān)于該類詳細(xì)的解析將在自動(dòng)注入原理與AutowiredAnnotationBeanPostProcessor 一文中

2.2.7 DestructionAwareBeanPostProcessor

BeanPostProcessor的子接口,用于添加銷毀前回調(diào)。典型用法是對(duì)特定bean類型調(diào)用定制的銷毀回調(diào),匹配相應(yīng)的初始化回調(diào)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容