BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring
作者:chun_soft 发布时间:2023-11-24 12:56:16
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注册。
来源:https://blog.csdn.net/ztchun/article/details/90814135


猜你喜欢
- 摘要:vs2019新鲜出炉,配置opencv又有哪些不一样呢,这个教程将会一步一步的教你如何配置opencv和跑动opencv一个简单的项目
- 在Thread中注入Bean无效在Spring项目中,有时需要新开线程完成一些复杂任务,而线程中可能需要注入一些服务。而通过Spring注入
- 一、概述 在C和C++语言中都有assert关键,表示断言。在Java中,同样也有assert关键字,表示断言,用法和含义都差不多
- 介绍:unity界面开发,会用到很多导航的按钮,他们是公共的,单击其中一个按钮,显示对应的界面。unity中,UGUI自带Toggle组件,
- 限流背景在早期的计算机领域,限流技术(time limiting)被用做控制网络接口收发通信数据的速率。可以用来优化性能,减少延迟和提高带宽
- 对于分布式应用来说,最开始遇到的问题就是 session 的存储了,解决方案大致有如下几种使用 spring-session 它可以把 se
- spring 多文件配置:1、properties文件2、YAML文件一、properties文件在 Spring Boot 中, 多环境配
- 本文实例讲述了C#实现对二维数组排序的方法。分享给大家供大家参考。具体实现方法如下:/// <summary>/// A gen
- 本文实例讲述了Java数组传递及可变参数操作。分享给大家供大家参考,具体如下:方法可以操作传递和返回基本数据类型,但是方法中也可用来传递和返
- 工欲善其事,必先利其器,对于想要深入学习Android源码,必须先掌握Android编译命令.一、引言关于Android Build系统,这
- OSS不支持通过一个网络地址来上传图片,所以若想将网络上的图片上传到OSS上需要走点弯路。1、通过链接将图片下载到本地的一个文件夹下面2、用
- Mybatis-Plus将字段设置为null项目场景:最近在做一个需求的时候需要把数据库中的某个字段设置为空问题描述:在代码中通过set方法
- 写这篇文章,做份备忘,简单滴展示一个带进度条的Webview示例,进度条位于Webview上面.示例图如下:主Activity代码:pack
- 目录微服务微服务架构SpringCould简介环境搭建1. 创建数据库2. 新建一个子模块api3. 新建一个子模块provider作为服务
- CancellationTokenCancellationToken有一个构造函数,可以传入一个bool类型表示当前的Cancellatio
- in查询 <foreach>循环问题当我在做in查询的时候,发现在网上有很多种写法:接口public List<CaseR
- 一致性哈希节点的增加和减少,大部分节点的 Hash一致package consistenthashimport ("hash/cr
- 目录一、连接查询:1、多对一:2、一对多:3、多对多:二、嵌套查询:1、多对一:2、一对多:首先在mysql中确立表:#表一:地址国家表CR
- Java环境部署下载所需软件和依赖安装 jdk路径可选别的盘。但是指向时得注意我自己时装在 F 盘的,在f盘里新建文件夹 Java,Java
- springboot扩展MVC自定义 config -> SpringMvcConfig.java下边就是扩展springMVC的模板