BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

 更新时间:2022年03月24日 14:39:54   作者:chun_soft  
这篇文章主要介绍了BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

1、理论

一般如果想将类注册到spring容器,让spring来完成实例化,常用方式如下:

  • xml中通过bean节点来配置;
  • 使用@Service、@Controller、@Conponent等注解。

最近在研究通过Spring初始化时扫描自定义注解,查到了通过实现BeanDefinitionRegistryPostProcessor获取Bean,从而获得自定义注解。

Spring支持我们通过代码来将指定的类注册到spring容器中。

Spring容器初始化时,从资源中读取到bean的相关定义后,保存在BeanDefinitionMap,在实例化bean的操作就是依据这些bean的定义来做的,而在实例化之前,Spring允许我们通过自定义扩展来改变bean的定义,定义一旦变了,后面的实例也就变了,而beanFactory后置处理器,即BeanFactoryPostProcessor就是用来改变bean定义的。

通过invokeBeanFactoryPostProcessors方法用来找出所有beanFactory后置处理器,并且调用这些处理器来改变bean的定义。

BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口,BeanFactoryPostProcessor的实现类在其postProcessBeanFactory方法被调用时,可以对bean的定义进行控制,因此BeanDefinitionRegistryPostProcessor的实现类一共要实现以下两个方法:

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException

该方法的实现中,主要用来对bean定义做一些改变。

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException

该方法用来注册更多的bean到spring容器中,详细观察入参BeanDefinitionRegistry接口,看看这个参数能带给我们什么能力。

从BeanDefinitionRegistry可以看到,BeanDefinitionRegistry提供了丰富的方法来操作BeanDefinition,判断、注册、移除等方法都准备好了,我们在编写postProcessBeanDefinitionRegistry方法的内容时,就能直接使用入参registry的这些方法来完成判断和注册、移除等操作。

org.springframework.context.support.AbstractApplicationContext#refresh中的invokeBeanFactoryPostProcessors(beanFactory);

用来找出所有beanFactory后置处理器,并且调用这些处理器来改变bean的定义。

invokeBeanFactoryPostProcessors(beanFactory)实际上是委托

org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

方法处理的。

首先处理BeanFactoryPostProcessor中的内容:

所有实现了BeanDefinitionRegistryPostProcessor接口的bean,其postProcessBeanDefinitionRegistry方法都会调用,然后再调用其postProcessBeanFactory方法,这样一来,我们如果自定义了BeanDefinitionRegistryPostProcessor接口的实现类,那么我们开发的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法都会被执行一次;

boolean reiterate = true;
while (reiterate) {
    reiterate = false;
    //查出所有实现了BeanDefinitionRegistryPostProcessor接口的bean名称
    postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    for (String ppName : postProcessorNames) {
        //前面的逻辑中,已经对实现了PriorityOrdered和Ordered的bean都处理过了,因此通过processedBeans过滤,processedBeans中没有的才会在此处理
        if (!processedBeans.contains(ppName)) {
            //根据名称和类型获取bean
            BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
            //把已经调用过postProcessBeanDefinitionRegistry方法的bean全部放在registryPostProcessors中
            registryPostProcessors.add(pp);
            //把已经调用过postProcessBeanDefinitionRegistry方法的bean的名称全部放在processedBeans中
            processedBeans.add(ppName);
            //执行此bean的postProcessBeanDefinitionRegistry方法
            pp.postProcessBeanDefinitionRegistry(registry);
            //改变退出while的条件
            reiterate = true;
        }
    }
}
/registryPostProcessors中保存了所有执行过postProcessBeanDefinitionRegistry方法的bean,
//现在再来执行这些bean的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
//regularPostProcessors中保存的是所有入参中带来的BeanFactoryPostProcessor实现类,并且这里面已经剔除了BeanDefinitionRegistryPostProcessor的实现类,现在要让这些bean执行postProcessBeanFactory方法

2、实战代码

public class AnnotationScannerConfigurer implements BeanDefinitionRegistryPostProcessor {
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
		// 创建一个bean的定义类的对象
		RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestServiceImpl.class);
		// 将Bean 的定义注册到Spring环境
		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可以动态将Bean注册。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java实现二分搜索树的示例代码

    Java实现二分搜索树的示例代码

    二分搜索树是一颗二叉树,二分搜索树每个节点的左子树的值都小于该节点的值,每个节点右子树的值都大于该节点的值。本文将利用Java实现二分搜索树,需要的可以参考一下
    2022-03-03
  • java Socket实现简单模拟HTTP服务器

    java Socket实现简单模拟HTTP服务器

    这篇文章主要介绍了java Socket实现简单模拟HTTP服务器,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 从零开始SSM搭建步骤(图文)

    从零开始SSM搭建步骤(图文)

    这篇文章主要介绍了从零开始SSM搭建步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • IntelliJ IDEA 安装教程2019.09.23(最新版)

    IntelliJ IDEA 安装教程2019.09.23(最新版)

    本文通过图文并茂的形式给大家介绍了IntelliJ IDEA 安装教程2019.09.23最新版,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • JavaEE中struts2实现文件上传下载功能实例解析

    JavaEE中struts2实现文件上传下载功能实例解析

    这篇文章主要为大家详细介绍了JavaEE中struts2实现文件上传下载功能实例,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • SpringBoot中自定义注解实现控制器访问次数限制实例

    SpringBoot中自定义注解实现控制器访问次数限制实例

    本篇文章主要介绍了SpringBoot中自定义注解实现控制器访问次数限制实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-04-04
  • java string类的常用方法详细介绍

    java string类的常用方法详细介绍

    在开发过程中经常会使用到java string类的方法,本文将以此问题进行详细介绍
    2012-11-11
  • SpringBoot使用Swagger范例讲解

    SpringBoot使用Swagger范例讲解

    Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化 Restful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许API来始终保持同步
    2022-07-07
  • Spring中@Qualifier注解的用法

    Spring中@Qualifier注解的用法

    但凡有点开发经验,多多少少可能都遇到过@Qualifier注解的使用场景,本文主要介绍了Spring中@Qualifier注解的用法,感兴趣的可以了解一下
    2023-11-11
  • 使用Hibernate根据实体类自动生成表的方法

    使用Hibernate根据实体类自动生成表的方法

    这篇文章主要介绍了使用Hibernate根据实体类自动生成表的方法,该篇提供了两种方法,可以根据需要选择其一,希望对你有所帮助,如有不对的地方还望指正
    2023-03-03

最新评论