写在前面

在前面的文章中,我们学习了如何使用@Import注解向Spring容器中导入bean,可以使用@Import注解快速向容器中导入bean,小伙伴们可以参见《【Spring注解驱动开发】使用@Import注解给容器中快速导入一个组件》。可以在@Import注解中使用ImportSelector接口导入bean,小伙伴们可以参见《【Spring注解驱动开发】在@Import注解中使用ImportSelector接口导入bean》一文。今天,我们就来说说,如何在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean。

项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotation

ImportBeanDefinitionRegistrar概述

概述

我们先来看看ImportBeanDefinitionRegistrar是个什么鬼,点击进入ImportBeanDefinitionRegistrar源码,如下所示。

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官方在动态注册bean时,大部分套路其实是使用ImportBeanDefinitionRegistrar接口。

所有实现了该接口的类都会被ConfigurationClassPostProcessor处理,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口,所以ImportBeanDefinitionRegistrar中动态注册的bean是优先于依赖其的bean初始化的,也能被aop、validator等机制处理。

使用方法

ImportBeanDefinitionRegistrar需要配合@Configuration和@Import注解,@Configuration定义Java格式的Spring配置文件,@Import注解导入实现了ImportBeanDefinitionRegistrar接口的类。

ImportBeanDefinitionRegistrar实例

既然ImportBeanDefinitionRegistrar是一个接口,那我们就创建一个MyImportBeanDefinitionRegistrar类,实现ImportBeanDefinitionRegistrar接口,如下所示。

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注解驱动开发不再迷茫。

【Spring注解驱动开发】在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean的更多相关文章

  1. 【String注解驱动开发】面试官让我说说:如何使用FactoryBean向Spring容器中注册bean?

    写在前面 在前面的文章中,我们知道可以通过多种方式向Spring容器中注册bean.可以使用@Configuration结合@Bean向Spring容器中注册bean:可以按照条件向Spring容器中 ...

  2. 【Spring注解驱动开发】使用@Import注解给容器中快速导入一个组件

    写在前面 我们可以将一些bean组件交由Spring管理,并且Spring支持单实例bean和多实例bean.我们自己写的类,可以通过包扫描+标注注解(@Controller.@Servcie.@Re ...

  3. 【Spring注解驱动开发】在@Import注解中使用ImportSelector接口导入bean

    写在前面 在上一篇关于Spring的@Import注解的文章<[Spring注解驱动开发]使用@Import注解给容器中快速导入一个组件>中,我们简单介绍了如何使用@Import注解给容器 ...

  4. 【String注解驱动开发】如何按照条件向Spring容器中注册bean?这次我懂了!!

    写在前面 当bean是单实例,并且没有设置懒加载时,Spring容器启动时,就会实例化bean,并将bean注册到IOC容器中,以后每次从IOC容器中获取bean时,直接返回IOC容器中的bean,不 ...

  5. 【Spring注解驱动开发】面试官:如何将Service注入到Servlet中?朋友又栽了!!

    写在前面 最近,一位读者出去面试前准备了很久,信心满满的去面试.没想到面试官的一个问题把他难住了.面试官的问题是这样的:如何使用Spring将Service注入到Servlet中呢?这位读者平时也是很 ...

  6. 0、Spring 注解驱动开发

    0.Spring注解驱动开发 0.1 简介 <Spring注解驱动开发>是一套帮助我们深入了解Spring原理机制的教程: 现今SpringBoot.SpringCloud技术非常火热,作 ...

  7. 【Spring注解驱动开发】组件注册-@ComponentScan-自动扫描组件&指定扫描规则

    写在前面 在实际项目中,我们更多的是使用Spring的包扫描功能对项目中的包进行扫描,凡是在指定的包或子包中的类上标注了@Repository.@Service.@Controller.@Compon ...

  8. 【Spring注解驱动开发】自定义TypeFilter指定@ComponentScan注解的过滤规则

    写在前面 Spring的强大之处不仅仅是提供了IOC容器,能够通过过滤规则指定排除和只包含哪些组件,它还能够通过自定义TypeFilter来指定过滤规则.如果Spring内置的过滤规则不能够满足我们的 ...

  9. 【Spring注解驱动开发】使用@Scope注解设置组件的作用域

    写在前面 Spring容器中的组件默认是单例的,在Spring启动时就会实例化并初始化这些对象,将其放到Spring容器中,之后,每次获取对象时,直接从Spring容器中获取,而不再创建对象.如果每次 ...

随机推荐

  1. CSS实现漂亮的小水球效果

    先看效果图: 代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...

  2. IO流基础,创建File对象与方法是用

    1.io流主要用途读取本地文件或服务器文件,进行本地或者服务器开呗工作 构造函数   绝对路径够构造方法:    File f = new File("D:\\test\\a.txt&quo ...

  3. MyBatis通过注解方式批量添加、修改、删除

    唯能极于情,故能极于剑 注: 本文转载于:CodeCow · 程序牛 的个人博客:http://www.codecow.cn/ 一.数据库实体DO public class User implemen ...

  4. Flutter 使用Navigator进行局部跳转页面

    老孟导读:Navigator组件使用的频率不是很高,但在一些场景下非常适用,比如局部表单多页填写.底部导航一直存在,每个tab各自导航场景. Navigator 是管理路由的控件,通常情况下直接使用N ...

  5. centos的安装

    直接给大家截图说明吧,简洁明了. 休闲吃瓜时光 选择语言  这边看个人  当然推荐英语 设置root密码 将自己要设置的信息填写进去即可 然后又是休闲吃瓜时光..... 下来登录即可 然后可以看到 这 ...

  6. 一键部署open***服务

    一键部署超级简单易用的openvpn服务器,支持多证书+多账号[密码]认证 一. 服务器端部署 项目地址:https://github.com/guoew/openvpn-install 1.1. 下 ...

  7. Error C2079 'CMFCPropertySheet::m_wndOutlookBar' uses undefined class 'CMFCOutlookBar'

    Severity Code Description Project File Line Suppression StateError C2079 'CMFCPropertySheet::m_wndOu ...

  8. 50个SQL语句(MySQL版) 建表 插入数据

    本学期正在学习数据库,前段时间老师让我们做一下50个经典SQL语句,当时做的比较快,有一些也是百度的,自我感觉理解的不是很透彻. 所以从本篇随笔开始,我将进行50个经典SQL语句的复盘,加深理解. 答 ...

  9. Spring Boot笔记(三) springboot 集成 Quartz 定时任务

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 1. 在 pom.xml 中 添加 Quartz 所需要 的 依赖 <!--定时器 quartz- ...

  10. java实现矩形区域的交和并

    在编写图形界面软件的时候,经常会遇到处理两个矩形的关系. 如图[1.jpg]所示,矩形的交集指的是:两个矩形重叠区的矩形,当然也可能不存在(参看[2.jpg]).两个矩形的并集指的是:能包含这两个矩形 ...