【Spring註解驅動開發】在@Import註解中使用ImportBeanDefinitionRegistrar向容器中註冊bean

寫在前面

在前面的文章中,咱們學習瞭如何使用@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是個什麼鬼,點擊進入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實例

既然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註解驅動開發再也不迷茫。

相關文章
相關標籤/搜索