BeanDefinitionRegistryPostProcessor如何動態(tài)注冊Bean到Spring
1、理論
一般如果想將類注冊到spring容器,讓spring來完成實例化,常用方式如下:
- xml中通過bean節(jié)點來配置;
- 使用@Service、@Controller、@Conponent等注解。
最近在研究通過Spring初始化時掃描自定義注解,查到了通過實現(xiàn)BeanDefinitionRegistryPostProcessor獲取Bean,從而獲得自定義注解。
Spring支持我們通過代碼來將指定的類注冊到spring容器中。
Spring容器初始化時,從資源中讀取到bean的相關(guān)定義后,保存在BeanDefinitionMap,在實例化bean的操作就是依據(jù)這些bean的定義來做的,而在實例化之前,Spring允許我們通過自定義擴展來改變bean的定義,定義一旦變了,后面的實例也就變了,而beanFactory后置處理器,即BeanFactoryPostProcessor就是用來改變bean定義的。
通過invokeBeanFactoryPostProcessors方法用來找出所有beanFactory后置處理器,并且調(diào)用這些處理器來改變bean的定義。
BeanDefinitionRegistryPostProcessor繼承了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor的實現(xiàn)類在其postProcessBeanFactory方法被調(diào)用時,可以對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方法的內(nèi)容時,就能直接使用入?yún)egistry的這些方法來完成判斷和注冊、移除等操作。
org.springframework.context.support.AbstractApplicationContext#refresh中的invokeBeanFactoryPostProcessors(beanFactory);
用來找出所有beanFactory后置處理器,并且調(diào)用這些處理器來改變bean的定義。
invokeBeanFactoryPostProcessors(beanFactory)實際上是委托
org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
方法處理的。
首先處理BeanFactoryPostProcessor中的內(nèi)容:
所有實現(xiàn)了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry方法都會調(diào)用,然后再調(diào)用其postProcessBeanFactory方法,這樣一來,我們?nèi)绻远x了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)調(diào)用過postProcessBeanDefinitionRegistry方法的bean全部放在registryPostProcessors中 registryPostProcessors.add(pp); //把已經(jīng)調(diào)用過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。
這種方法沒滿足我的實際需求。
總結(jié)下
BeanFactoryPostProcessor可以修改各個注冊的Bean,BeanDefinitionRegistryPostProcessor可以動態(tài)將Bean注冊。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java Socket實現(xiàn)簡單模擬HTTP服務(wù)器
這篇文章主要介紹了java Socket實現(xiàn)簡單模擬HTTP服務(wù)器,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05IntelliJ IDEA 安裝教程2019.09.23(最新版)
本文通過圖文并茂的形式給大家介紹了IntelliJ IDEA 安裝教程2019.09.23最新版,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-10-10JavaEE中struts2實現(xiàn)文件上傳下載功能實例解析
這篇文章主要為大家詳細介紹了JavaEE中struts2實現(xiàn)文件上傳下載功能實例,感興趣的小伙伴們可以參考一下2016-05-05SpringBoot中自定義注解實現(xiàn)控制器訪問次數(shù)限制實例
本篇文章主要介紹了SpringBoot中自定義注解實現(xiàn)控制器訪問次數(shù)限制實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-04-04