BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

作者:chun_soft 时间:2023-11-24 12:56:16 

1、理论

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

  • xml中通过bean节点来配置;

  • 使用@Service、@Controller、@Conponent等注解。

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

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

BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

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

BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

通过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接口,看看这个参数能带给我们什么能力。

BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

从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());

方法处理的。

BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

首先处理BeanFactoryPostProcessor中的内容:

BeanDefinitionRegistryPostProcessor如何动态注册Bean到Spring

所有实现了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

标签:动态注册,Spring,Bean
0
投稿

猜你喜欢

  • Android开发之对话框案例详解(五种对话框)

    2021-08-07 11:37:47
  • Android Room数据库多表查询的使用实例

    2022-11-07 02:49:49
  • android阅读器长按选择文字功能实现代码

    2023-09-16 08:48:42
  • 常用json与javabean互转的方法实现

    2023-01-07 14:24:19
  • Java中弱引用和软引用的区别以及虚引用和强引用介绍

    2023-01-23 18:55:33
  • iOS实现从背景图中取色的代码

    2023-07-06 15:18:32
  • SpringBoot2.3新特性优雅停机详解

    2023-11-28 07:59:43
  • Java中MessageDigest来实现数据加密的方法

    2023-05-18 01:13:49
  • Spring Cache框架应用介绍

    2023-06-15 22:32:59
  • C#中dynamic关键字的正确用法(推荐)

    2023-11-12 09:20:22
  • C#中派生类调用基类构造函数用法分析

    2022-01-14 08:10:22
  • spring基于注解配置实现事务控制操作

    2021-12-07 11:58:24
  • 基于C#生成随机数示例

    2023-06-27 08:40:17
  • 如何使用LinQ To Object把数组或DataTable中的数据进行向上汇总

    2022-04-05 17:07:33
  • java基础之包装类的介绍及使用

    2023-01-10 17:45:29
  • Mybatis配置之<typeAliases>别名配置元素解析

    2023-08-02 03:09:54
  • java编写贪吃蛇小游戏

    2023-06-19 01:49:54
  • JAVA 格式化日期、时间的方法

    2023-10-17 07:53:22
  • Java动态代 理分析及简单实例

    2023-11-24 21:14:56
  • Java如何在PDF中添加ToolTip工具提示

    2021-12-31 12:12:53
  • asp之家 软件编程 m.aspxhome.com