在前面的文章中,咱們學習瞭如何使用@Import註解向Spring容器中導入bean,可使用@Import註解快速向容器中導入bean,小夥伴們能夠參見《【Spring註解驅動開發】使用@Import註解給容器中快速導入一個組件》。能夠在@Import註解中使用ImportSelector接口導入bean,小夥伴們能夠參見《【Spring註解驅動開發】在@Import註解中使用ImportSelector接口導入bean》一文。今天,咱們就來講說,如何在@Import註解中使用ImportBeanDefinitionRegistrar向容器中註冊bean。java
項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotationgit
咱們先來看看ImportBeanDefinitionRegistrar是個什麼鬼,點擊進入ImportBeanDefinitionRegistrar源碼,以下所示。github
package org.springframework.context.annotation; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.core.type.AnnotationMetadata; public interface ImportBeanDefinitionRegistrar { default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { registerBeanDefinitions(importingClassMetadata, registry); } default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } }
由源碼能夠看出,ImportBeanDefinitionRegistrar本質上是一個接口。在ImportBeanDefinitionRegistrar接口中,有一個registerBeanDefinitions()方法,經過registerBeanDefinitions()方法,咱們能夠向Spring容器中註冊bean實例。spring
Spring官方在動態註冊bean時,大部分套路實際上是使用ImportBeanDefinitionRegistrar接口。bash
全部實現了該接口的類都會被ConfigurationClassPostProcessor處理,ConfigurationClassPostProcessor實現了BeanFactoryPostProcessor接口,因此ImportBeanDefinitionRegistrar中動態註冊的bean是優先於依賴其的bean初始化的,也能被aop、validator等機制處理。微信
ImportBeanDefinitionRegistrar須要配合@Configuration和@Import註解,@Configuration定義Java格式的Spring配置文件,@Import註解導入實現了ImportBeanDefinitionRegistrar接口的類。框架
既然ImportBeanDefinitionRegistrar是一個接口,那咱們就建立一個MyImportBeanDefinitionRegistrar類,實現ImportBeanDefinitionRegistrar接口,以下所示。ide
package io.mykit.spring.plugins.register.condition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; /** * @author binghe * @version 1.0.0 * @description ImportBeanDefinitionRegistrar的實現類 */ public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata: 當前類的註解信息 * BeanDefinitionRegistry:BeanDefinition註冊類 * 經過調用BeanDefinitionRegistry接口的registerBeanDefinition()方法,能夠將全部須要添加到容器中的bean注入到容器中。 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){ } }
能夠看到,這裏,咱們先建立了MyImportBeanDefinitionRegistrar類的大致框架。接下來,咱們在PersonConfig2類上的@Import註解中,添加MyImportBeanDefinitionRegistrar類,以下所示。學習
@Configuration @Import({Department.class, Employee.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class PersonConfig2 {
接下來,建立一個Company類,做爲測試測試ImportBeanDefinitionRegistrar接口的bean,以下所示。測試
package io.mykit.spring.plugins.register.bean; /** * @author binghe * @version 1.0.0 * @description 測試ImportBeanDefinitionRegistrar接口的使用 */ public class Company { }
接下來,就要實現MyImportBeanDefinitionRegistrar類中的registerBeanDefinitions()方法的邏輯了,添加邏輯後的registerBeanDefinitions()方法以下所示。
/** * AnnotationMetadata: 當前類的註解信息 * BeanDefinitionRegistry:BeanDefinition註冊類 * 經過調用BeanDefinitionRegistry接口的registerBeanDefinition()方法,能夠將全部須要添加到容器中的bean注入到容器中。 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){ boolean employee = registry.containsBeanDefinition("employee"); boolean department = registry.containsBeanDefinition("department"); if (employee && department){ BeanDefinition beanDefinition = new RootBeanDefinition(Company.class); registry.registerBeanDefinition("company", beanDefinition); } }
registerBeanDefinitions()方法的實現邏輯很簡單,就是判斷Spring容器中是否同時存在以employee命名的bean和以department命名的bean,若是同時存在以employee命名的bean和以department命名的bean,則向Spring容器中注入一個以company命名的bean。
接下來,咱們就運行SpringBeanTest類中的testAnnotationConfig7()方法來進行測試,輸出結果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001
能夠看到,在輸出結果中,並無看到「company」,這是由於輸出結果中存在io.mykit.spring.plugins.register.bean.Department和io.mykit.spring.plugins.register.bean.Employee,並不存在咱們代碼邏輯中的department和employee。因此,咱們將registerBeanDefinitions()方法的邏輯稍微修改下,修改後的代碼以下所示。
/** * AnnotationMetadata: 當前類的註解信息 * BeanDefinitionRegistry:BeanDefinition註冊類 * 經過調用BeanDefinitionRegistry接口的registerBeanDefinition()方法,能夠將全部須要添加到容器中的bean注入到容器中。 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){ boolean employee = registry.containsBeanDefinition(Employee.class.getName()); boolean department = registry.containsBeanDefinition(Department.class.getName()); if (employee && department){ BeanDefinition beanDefinition = new RootBeanDefinition(Company.class); registry.registerBeanDefinition("company", beanDefinition); } }
接下來,咱們再次運行SpringBeanTest類中的testAnnotationConfig7()方法來進行測試,輸出結果信息以下所示。
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory personConfig2 io.mykit.spring.plugins.register.bean.Department io.mykit.spring.plugins.register.bean.Employee io.mykit.spring.plugins.register.bean.User io.mykit.spring.plugins.register.bean.Role person binghe001 company
能夠看到,此時輸出了company,說明Spring容器中已經成功註冊了以company命名的bean。
好了,我們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一塊兒學習一塊兒進步!!
項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation
若是以爲文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公衆號,跟冰河學習Spring註解驅動開發。公衆號回覆「spring註解」關鍵字,領取Spring註解驅動開發核心知識圖,讓Spring註解驅動開發再也不迷茫。