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

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

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

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

首先處理BeanFactoryPostProcessor中的內容:

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

