BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

目录
  • 1、理论
  • 2、实战代码
  • 总结下

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注册。

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

(0)

相关推荐

  • Spring Bean是如何初始化的详解

    目录 前言 三级缓存 doGetBean createBean doCreateBean instantiateBean instantiate instantiateClass 注入 AutowiredAnnotationBeanPostProcessor分析 postProcessProperties 如何实现bean注入的 总结 前言 做Java都有很多年了,一直有一个疑惑: Spring 如何初始化bean,怎么调用反射实例化对象的,自己动手来解除这个疑惑. 过去我认为spring be

  • springboot-启动bean冲突的解决

    目录 启动bean冲突 启动提示bean重复问题 先说结论 原理 启动bean冲突 在一次启动中遇到了bean冲突的问题,提示存在两个名称重复的bean org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.test.api.Application]; nested exception is org.springframework.conte

  • 解决springboot生成bean名称冲突(AnnotationBeanNameGenerator)

    目录 springboot生成bean名称冲突 问题描述 解决问题 自定义bean对象重名问题 springboot生成bean名称冲突 问题描述 我们再使用springboot的时候,在不同的文件目录下,可能存在相同名称的java类,这个时候会报bean name冲突错误 首先我们来了解下,springboot生成bean名称的原理 当Component,Respository,Service,Controller注解的value树形没有自定义时,会根据类的名称生成一个短的bean name.

  • spring Bean的初始化过程解析

    AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors 使用BeanPostProcessor收集带有注解的方法和属性,方便下面初始化时调用.org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors protected void

  • springboot中如何判断某个bean是否存在

    目录 如何判断某个bean是否存在 使用@Bean的好处与坏处 如何判断某个bean是否存在 ApplicationContext ctx = SpringUtil.getContext(); String[] beanNames = ctx.getBeanDefinitionNames(); Arrays.sort(beanNames); for (String beanName : beanNames) { //全部bean System.out.println(beanName); } /

  • BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

    目录 1.理论 2.实战代码 总结下 1.理论 一般如果想将类注册到spring容器,让spring来完成实例化,常用方式如下: xml中通过bean节点来配置: 使用@Service.@Controller.@Conponent等注解. 最近在研究通过Spring初始化时扫描自定义注解,查到了通过实现BeanDefinitionRegistryPostProcessor获取Bean,从而获得自定义注解. Spring支持我们通过代码来将指定的类注册到spring容器中. Spring容器初始化

  • 向Spring IOC 容器动态注册bean实现方式

    目录 本文的大纲 从一个需求谈起 Spring Bean的生命周期再完善 BeanDefinition Bean 加入IOC容器的几种方式 从spring容器中动态添加或移除bean 本文的大纲 从一个需求谈起 这周遇到了这样一个需求,从第三方的数据库中获取值,只是一个简单的分页查询,处理这种问题,我一般都是在配置文件中配置数据库的地址等相关信息,然后在Spring Configuration 注册数据量连接池的bean,然后再将数据库连接池给JdbcTemplate, 但是这种的缺陷是,假设填

  • Spring之动态注册bean的实现方法

    Spring之动态注册bean 什么场景下,需要主动向Spring容器注册bean呢? 如我之前做个的一个支持扫表的基础平台,使用者只需要添加基础配置 + Groovy任务,就可以丢到这个平台上面来运行了,而这个基础平台是一直都在运行的,所以在新来任务时,最直观需要注册的就是 DataSource 数据源这个bean了,那么可以怎么玩? I. 主动注册Bean支持 借助BeanDefinition来实现bean的定义,从最终的使用来看,代码比较少,几行而已 public <T> T regis

  • Spring运行时动态注册bean的方法

    在spring运行时,动态的添加bean,dapeng框架在解析xml的字段时,使用到了动态注册,注册了一个实现了FactoryBean类! 定义一个没有被Spring管理的Controller public class UserController implements InitializingBean{ private UserService userService; public UserService getUserService() { return userService; } pu

  • SpringBean和Controller实现动态注册与注销过程详细讲解

    目录 说明 注册和注销工具类 编写测试用例 测试结果 注册Service 注册controller 注销Controller 部分场景下可能需要下载远程jar包,然后注册jar包中的Bean和Controller 说明 这里的Bean 一般特指 Service层的服务类,Controller本质上也是Bean 注册和注销工具类 这里用了一些 hutool的工具类,hutools是一个不错的基础工具集. package cn.guzt.utils; import cn.hutool.extra.s

  • JSP 开发之Spring Boot 动态创建Bean

    JSP 开发之Spring Boot 动态创建Bean 1.通过注解@Import导入方式创建 a.新建MyImportBeanDefinitionRegistrar注册中心 Java代码 import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; import org

  • Spring Boot如何动态创建Bean示例代码

    前言 本文主要给大家介绍了关于Spring Boot动态创建Bean的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. SpringBoot测试版本:1.3.4.RELEASE 参考代码如下: package com.spring.configuration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.su

  • Spring动态注册多数据源的实现方法

    最近在做SaaS应用,数据库采用了单实例多schema的架构(详见参考资料1),每个租户有一个独立的schema,同时整个数据源有一个共享的schema,因此需要解决动态增删.切换数据源的问题. 在网上搜了很多文章后,很多都是讲主从数据源配置,或都是在应用启动前已经确定好数据源配置的,甚少讲在不停机的情况如何动态加载数据源,所以写下这篇文章,以供参考. 使用到的技术 Java8 Spring + SpringMVC + MyBatis Druid连接池 Lombok (以上技术并不影响思路实现,

  • 如何在Spring中使用编码方式动态配置Bean详解

    bean与spring容器的关系 Bean配置信息定义了Bean的实现及依赖关系,Spring容器根据各种形式的Bean配置信息在容器内部建立Bean定义注册表,然后根据注册表加载.实例化Bean,并建立Bean和Bean的依赖关系,最后将这些准备就绪的Bean放到Bean缓存池中,以供外层的应用程序进行调用. 本文将给大家详细介绍关于在Spring中使用编码方式动态配置Bean的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 1 DefaultListableBea

  • Spring BPP中如何优雅的创建动态代理Bean详解

    v一.前言 本文章所讲并没有基于Aspectj,而是直接通过Cglib以及ProxyFactoryBean去创建代理Bean.通过下面的例子,可以看出Cglib方式创建的代理Bean和ProxyFactoryBean创建的代理Bean的区别. v二.基本测试代码 测试实体类,在BPP中创建BppTestDepBean类型的代理Bean. @Component public static class BppTestBean { @Autowired private BppTestDepBean d

随机推荐