BeanDefinitionRegistryPostProcessor如何動(dòng)態(tài)注冊(cè)Bean到Spring
1、理論
一般如果想將類注冊(cè)到spring容器,讓spring來(lái)完成實(shí)例化,常用方式如下:
- xml中通過(guò)bean節(jié)點(diǎn)來(lái)配置;
- 使用@Service、@Controller、@Conponent等注解。
最近在研究通過(guò)Spring初始化時(shí)掃描自定義注解,查到了通過(guò)實(shí)現(xiàn)BeanDefinitionRegistryPostProcessor獲取Bean,從而獲得自定義注解。
Spring支持我們通過(guò)代碼來(lái)將指定的類注冊(cè)到spring容器中。

Spring容器初始化時(shí),從資源中讀取到bean的相關(guān)定義后,保存在BeanDefinitionMap,在實(shí)例化bean的操作就是依據(jù)這些bean的定義來(lái)做的,而在實(shí)例化之前,Spring允許我們通過(guò)自定義擴(kuò)展來(lái)改變bean的定義,定義一旦變了,后面的實(shí)例也就變了,而beanFactory后置處理器,即BeanFactoryPostProcessor就是用來(lái)改變bean定義的。

通過(guò)invokeBeanFactoryPostProcessors方法用來(lái)找出所有beanFactory后置處理器,并且調(diào)用這些處理器來(lái)改變bean的定義。
BeanDefinitionRegistryPostProcessor繼承了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor的實(shí)現(xiàn)類在其postProcessBeanFactory方法被調(diào)用時(shí),可以對(duì)bean的定義進(jìn)行控制,因此BeanDefinitionRegistryPostProcessor的實(shí)現(xiàn)類一共要實(shí)現(xiàn)以下兩個(gè)方法:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
該方法的實(shí)現(xiàn)中,主要用來(lái)對(duì)bean定義做一些改變。
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException
該方法用來(lái)注冊(cè)更多的bean到spring容器中,詳細(xì)觀察入?yún)eanDefinitionRegistry接口,看看這個(gè)參數(shù)能帶給我們什么能力。

從BeanDefinitionRegistry可以看到,BeanDefinitionRegistry提供了豐富的方法來(lái)操作BeanDefinition,判斷、注冊(cè)、移除等方法都準(zhǔn)備好了,我們?cè)诰帉?xiě)postProcessBeanDefinitionRegistry方法的內(nèi)容時(shí),就能直接使用入?yún)egistry的這些方法來(lái)完成判斷和注冊(cè)、移除等操作。
org.springframework.context.support.AbstractApplicationContext#refresh中的invokeBeanFactoryPostProcessors(beanFactory);
用來(lái)找出所有beanFactory后置處理器,并且調(diào)用這些處理器來(lái)改變bean的定義。
invokeBeanFactoryPostProcessors(beanFactory)實(shí)際上是委托
org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
方法處理的。

首先處理BeanFactoryPostProcessor中的內(nèi)容:

所有實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry方法都會(huì)調(diào)用,然后再調(diào)用其postProcessBeanFactory方法,這樣一來(lái),我們?nèi)绻远x了BeanDefinitionRegistryPostProcessor接口的實(shí)現(xiàn)類,那么我們開(kāi)發(fā)的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法都會(huì)被執(zhí)行一次;
boolean reiterate = true;
while (reiterate) {
reiterate = false;
//查出所有實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口的bean名稱
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//前面的邏輯中,已經(jīng)對(duì)實(shí)現(xiàn)了PriorityOrdered和Ordered的bean都處理過(guò)了,因此通過(guò)processedBeans過(guò)濾,processedBeans中沒(méi)有的才會(huì)在此處理
if (!processedBeans.contains(ppName)) {
//根據(jù)名稱和類型獲取bean
BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
//把已經(jīng)調(diào)用過(guò)postProcessBeanDefinitionRegistry方法的bean全部放在registryPostProcessors中
registryPostProcessors.add(pp);
//把已經(jīng)調(diào)用過(guò)postProcessBeanDefinitionRegistry方法的bean的名稱全部放在processedBeans中
processedBeans.add(ppName);
//執(zhí)行此bean的postProcessBeanDefinitionRegistry方法
pp.postProcessBeanDefinitionRegistry(registry);
//改變退出while的條件
reiterate = true;
}
}
}
/registryPostProcessors中保存了所有執(zhí)行過(guò)postProcessBeanDefinitionRegistry方法的bean,
//現(xiàn)在再來(lái)執(zhí)行這些bean的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
//regularPostProcessors中保存的是所有入?yún)⒅袔?lái)的BeanFactoryPostProcessor實(shí)現(xiàn)類,并且這里面已經(jīng)剔除了BeanDefinitionRegistryPostProcessor的實(shí)現(xiàn)類,現(xiàn)在要讓這些bean執(zhí)行postProcessBeanFactory方法
2、實(shí)戰(zhàn)代碼
public class AnnotationScannerConfigurer implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
// 創(chuàng)建一個(gè)bean的定義類的對(duì)象
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestServiceImpl.class);
// 將Bean 的定義注冊(cè)到Spring環(huán)境
beanDefinitionRegistry.registerBeanDefinition("testService", rootBeanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
// bean的名字為key, bean的實(shí)例為value
Map<String, Object> beanMap = configurableListableBeanFactory.getBeansWithAnnotation(AutoDiscoverClass.class);
}
其實(shí)在實(shí)際使用過(guò)程中,Spring啟動(dòng)時(shí)掃描自定義注解,是通過(guò)BeanFactoryPostProcessor接口的postProcessBeanFactory方法
configurableListableBeanFactory.getBeansWithAnnotation(AutoDiscoverClass.class);
獲取每一個(gè)有自定義注解的Bean。
這種方法沒(méi)滿足我的實(shí)際需求。
總結(jié)下
BeanFactoryPostProcessor可以修改各個(gè)注冊(cè)的Bean,BeanDefinitionRegistryPostProcessor可以動(dòng)態(tài)將Bean注冊(cè)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)二分搜索樹(shù)的示例代碼
二分搜索樹(shù)是一顆二叉樹(shù),二分搜索樹(shù)每個(gè)節(jié)點(diǎn)的左子樹(shù)的值都小于該節(jié)點(diǎn)的值,每個(gè)節(jié)點(diǎn)右子樹(shù)的值都大于該節(jié)點(diǎn)的值。本文將利用Java實(shí)現(xiàn)二分搜索樹(shù),需要的可以參考一下2022-03-03
java Socket實(shí)現(xiàn)簡(jiǎn)單模擬HTTP服務(wù)器
這篇文章主要介紹了java Socket實(shí)現(xiàn)簡(jiǎn)單模擬HTTP服務(wù)器,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
IntelliJ IDEA 安裝教程2019.09.23(最新版)
本文通過(guò)圖文并茂的形式給大家介紹了IntelliJ IDEA 安裝教程2019.09.23最新版,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10
JavaEE中struts2實(shí)現(xiàn)文件上傳下載功能實(shí)例解析
這篇文章主要為大家詳細(xì)介紹了JavaEE中struts2實(shí)現(xiàn)文件上傳下載功能實(shí)例,感興趣的小伙伴們可以參考一下2016-05-05
SpringBoot中自定義注解實(shí)現(xiàn)控制器訪問(wèn)次數(shù)限制實(shí)例
本篇文章主要介紹了SpringBoot中自定義注解實(shí)現(xiàn)控制器訪問(wèn)次數(shù)限制實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04
使用Hibernate根據(jù)實(shí)體類自動(dòng)生成表的方法
這篇文章主要介紹了使用Hibernate根據(jù)實(shí)體類自動(dòng)生成表的方法,該篇提供了兩種方法,可以根據(jù)需要選擇其一,希望對(duì)你有所幫助,如有不對(duì)的地方還望指正2023-03-03

