【BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 详细解答】

1、定义

BeanDefinitionRegistryPostProcessor 实际上是 BeanFactoryPostProcessor 的一个特殊化和功能更强的子接口

在 Spring 的 IoC 容器中,Bean 的定义(BeanDefinition) 与 Bean 的实例化 是两个阶段。而 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 正是介入这两个阶段的重要扩展点,开发者可以通过它们对 Spring 的 Bean 定义或 BeanFactory 进行定制化。

简单来说:

  • BeanDefinitionRegistryPostProcessor"征兵官" ,负责招募新士兵(注册新的BeanDefinition)
  • BeanFactoryPostProcessor"训练官" ,负责训练和调整已有士兵的属性(修改已注册的BeanDefinition)

下面进行详细对比。


2、BeanDefinitionRegistryPostProcessor (BDRPP)分析

1. 身份与继承关系:

它是 BeanFactoryPostProcessor子接口 。这意味着一个实现了 BeanDefinitionRegistryPostProcessor 的类,同时也是一个 BeanFactoryPostProcessor

2. 核心方法:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

3. 操作时机与目标:

它的执行时机早于 普通的 BeanFactoryPostProcessor

它操作的目标是 BeanDefinitionRegistry 。这个Registry就是Spring容器中用于注册、持有和管理所有BeanDefinition的"仓库"

4. 主要作用与权力:

它的核心权力是动态地、编程式地向Spring容器中注册全新的BeanDefinition。这包括:

  • 注册新的Bean:根据条件(如扫描特定路径、检查某个类是否存在)动态地向容器中添加新的Bean定义。
  • 移除已有的Bean定义:虽然不常用,但理论上也可以从Registry中移除某个BeanDefinition。
  • 当然,它也能做普通BFPP能做的事(获取和修改已存在的BeanDefinition),因为它最终也会执行 postProcessBeanFactory 方法。

5. 经典例子:

  • ConfigurationClassPostProcessor :这是Spring中最重要、最核心的BDRPP。它负责解析 @Configuration 类、扫描 @Component、处理 @Bean 方法等。正是这个处理器,才使得我们通过注解定义的Bean能够被注册到容器中。

3、BeanFactoryPostProcessor (BFPP)分析

1. 核心方法:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

2. 操作时机与目标:

它的执行时机晚于 BeanDefinitionRegistryPostProcessor

它操作的目标是 ConfigurableListableBeanFactory。这个BeanFactory已经包含了所有通过BDRPP注册好的BeanDefinition。

3. 主要作用与权力:

它的权力相对"小"一些,主要是对已经存在于BeanFactory中的BeanDefinition进行查询和修改 ,但不能注册全新的BeanDefinition。包括:

  • 修改Bean的属性值。
  • 修改Bean的作用域(Scope)。
  • 处理占位符(如 ${})。

4、执行流程与顺序

Spring容器的启动过程中,这两个处理器的执行有一个非常清晰的顺序:

  1. 实例化 所有 BeanFactoryPostProcessor(包括其子类BeanDefinitionRegistryPostProcessor)。
  2. 首先,调用所有 BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry 方法。
    • 这些处理器向容器中注册了大量新的BeanDefinition(例如,通过注解扫描到的Bean)。
  3. 然后,调用所有 BeanDefinitionRegistryPostProcessorpostProcessBeanFactory 方法(因为它们也实现了BFPP接口)。
  4. 最后,调用所有普通的 BeanFactoryPostProcessorpostProcessBeanFactory 方法。
    • 这些处理器对现在已经完整的BeanDefinition集合进行修改和调整。

5、对比总结表

特性 BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor
关系 BeanFactoryPostProcessor的扩展子接口 父接口
核心方法 postProcessBeanDefinitionRegistry postProcessBeanFactory
执行顺序 先执行 后执行 (在BDRPP的postProcessBeanFactory之后)
操作目标 BeanDefinitionRegistry (注册中心) ConfigurableListableBeanFactory (Bean工厂)
核心权力 注册、移除BeanDefinition (修改容器内容) 查询、修改已注册的BeanDefinition (调整容器内容)
典型应用 编程式注册Bean、注解扫描(ConfigurationClassPostProcessor) 修改属性、占位符解析(PropertySourcesPlaceholderConfigurer)

6、代码示例

java 复制代码
@Component
public class MyRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    // 第一阶段:注册新Bean
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 1. 动态注册一个全新的Bean
        RootBeanDefinition beanDefinition = new RootBeanDefinition(DynamicService.class);
        registry.registerBeanDefinition("dynamicService", beanDefinition);

        // 2. 也可以移除已有的Bean定义
        // if (registry.containsBeanDefinition("unwantedBean")) {
        //     registry.removeBeanDefinition("unwantedBean");
        // }
    }

    // 第二阶段:修改已注册的Bean(和普通BFPP一样)
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition bd = beanFactory.getBeanDefinition("someExistingBean");
        // ... 修改属性等操作
    }
}

@Component
public class MyNormalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    // 只在第三阶段执行
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 此时,名为 "dynamicService" 的Bean已经被注册,这里可以获取到它并进行修改
        BeanDefinition bd = beanFactory.getBeanDefinition("dynamicService");
        // ... 修改操作
    }
}

7、总结

你可以这样理解它们的职责划分:

  • BeanDefinitionRegistryPostProcessor :负责扫描注解@Configuration、@Bean 解析然后调用 BeanDefinitionRegistry 注册 这些带有注解的 Bean的原信息。(修改容器本身)
  • BeanFactoryPostProcessor :负责对以及存在的BeanDefination进行修改。(修改容器内的内容)

这种设计体现了Spring框架的"开放-封闭"原则,通过不同的扩展点,允许用户在容器生命周期的不同阶段注入不同的逻辑,提供了极大的灵活性。

相关推荐
qianmoq9 分钟前
第03章:无限流:generate()和iterate()的神奇用法
java
whitepure11 分钟前
万字详解JVM
java·jvm·后端
我崽不熬夜17 分钟前
Java的条件语句与循环语句:如何高效编写你的程序逻辑?
java·后端·java ee
我崽不熬夜1 小时前
Java中的String、StringBuilder、StringBuffer:究竟该选哪个?
java·后端·java ee
草明1 小时前
docker stats 增加一列容器名称的显示
java·开发语言·docker
期待のcode1 小时前
Maven的概念与Maven项目的创建
java·maven
我崽不熬夜1 小时前
Java中的基本数据类型和包装类:你了解它们的区别吗?
java·后端·java ee
每天学习一丢丢2 小时前
SpringBoot + Vue实现批量导入导出功能的标准方案
vue.js·spring boot·后端
我是廖志伟2 小时前
【jar包启动,每天生成一个日志文件】
java·jar
掉鱼的猫2 小时前
Solon StateMachine 实现状态机使用示例详解
java·状态机