Spring 高手之路 13——BeanFactoryPostProcessor 与 BeanDefinitionRegistryPostProcessor 解析
1. BeanFactoryPostProcessor 概览
1.1 解读 BeanFactoryPostProcessor
BeanFactoryPostProcessor
位于org.springframework.beans.factory.config
包中。它与BeanPostProcessor
有相似的核心逻辑,但它们之间的主要区别在于它们所操作的对象。BeanFactoryPostProcessor
的主要目的是对Bean
的配置元数据进行操作,这意味着它可以影响Bean
的初始配置数据。
在Spring IoC
容器实例化beans
之前,特别是除了BeanFactoryPostProcessor
之外的其他beans
,BeanFactoryPostProcessor
有权利修改这些beans
的配置。在Spring
中,所有的beans
在被完全实例化之前都是以BeanDefinition
的形式存在的。BeanFactoryPostProcessor
为我们提供了一个机会,使我们能够在bean
完全实例化之前调整和修改这些BeanDefinition
。对BeanDefinition
的任何修改都会影响后续的bean
实例化和初始化过程。
1.2. 如何使用 BeanFactoryPostProcessor
来看看BeanFactoryPostProcessor
能如何影响BeanDefinition
。
假设我们需要为一系列的Tint
对象赋值名字,这个名字就是bean
的名字,而且要在bean
实例化之前完成。
定义 bean
我们定义一个简单的Tint
抽象类以及其两个子类Blue
和Yellow
:
创建后置处理器
思路是在后置处理器中,我们可以获取到BeanFactory
,然后操作其中的BeanDefinition
。
运行测试
启动Spring
容器,查看结果:
运行之后,控制台打印Blue
对象的label
属性,显示后置处理器成功修改了bean
的属性。
替代方法
我们也可以使用BeanPostProcessor
达到BeanFactoryPostProcessor
相似的效果:
运行结果:
BeanPostProcessor 与 BeanFactoryPostProcessor 的对比
2. BeanDefinitionRegistryPostProcessor 深入探究
2.1 解读 BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor
是 Spring
容器的一个扩展点,主要用于在 Spring
容器完成对 Bean
的定义信息的加载后、但在它们真正实例化之前,进行额外的操作。
为了更好地理解,让我们用一个图书馆的类比:
想象一个新的图书馆正在组织其图书收藏。这个过程可以分为几个步骤:
制定书单:图书馆先列出了所有想要的书的名称和作者,但还没有实际购买书籍。在
Spring
中,这就类似于创建BeanDefinition
。在这个步骤后,但在图书馆真正购买书籍之前,假设图书馆收到了一个特别的捐赠列表(
BeanDefinitionRegistryPostProcessor
)。这个捐赠列表允许图书馆在正式购买书籍之前添加或修改书单。在Spring
中,这是使用BeanDefinitionRegistryPostProcessor
在实际的bean
实例化之前修改bean
定义的时机。按书单采购:此时,图书馆会按照更新后的书单进行购书。这个过程在
Spring
中类似于bean
的实例化和属性填充。
更佳专业化的描述如下:
BeanDefinitionRegistryPostProcessor
是Spring
中的一个高级扩展接口,继承自 BeanFactoryPostProcessor
。它提供了更为深入的方式来干预bean
定义的注册过程。
这个接口定义于 org.springframework.beans.factory.support
包内,它的特殊之处在于,除了能够像 BeanFactoryPostProcessor
那样修改已经注册的bean
定义(BeanDefinition
),还能向注册中心 BeanDefinitionRegistry
中动态地添加或移除bean
定义。
BeanDefinitionRegistryPostProcessor
提供了一个核心方法:postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
。通过该方法,我们可以直接操作 BeanDefinitionRegistry
,这是一个专门用于bean
定义注册的中心接口。它允许我们直接注册新的bean
定义、修改已有的bean
定义或者完全移除某些bean
定义。
使用这个接口的常见场景包括基于项目的特定条件动态地注册beans
,例如,可能只在某些环境中需要的beans
,或者基于配置选项动态地选择实现类。
与 BeanFactoryPostProcessor
的关键区别在于其执行时机。BeanDefinitionRegistryPostProcessor
的方法在所有其他 BeanFactoryPostProcessor
方法之前执行,这确保了它可以在其他处理器操作前先注册或修改bean
定义。
总的来说,BeanDefinitionRegistryPostProcessor
提供了一种在Spring
容器配置解析阶段动态介入的能力,允许我们在其他配置处理器介入之前,进行更为深入的bean
定义的调整和优化。
2.2 BeanDefinitionRegistryPostProcessor 的执行时机
执行时机用一张流程图表示如下:
加载配置:
Spring
从各种来源(如XML
文件、Java
配置、注解)加载配置信息。解析配置: 根据加载的配置,
Spring
创建对应的BeanDefinition
。注册 BeanDefinition: 解析完成后,
Spring
将这些BeanDefinition
对象注册到BeanDefinitionRegistry
中。执行 BeanDefinitionRegistryPostProcessor: 这个后置处理器提供了一个重要的扩展点,允许在所有
BeanDefinition
注册完毕后,但在Bean
实例化之前进行一些操作。例如:注册新的BeanDefinition
、修改或删除现有的BeanDefinition
。执行 BeanFactoryPostProcessor: 这个后置处理器提供了另一个扩展点,它主要允许查看或修改已经注册的
BeanDefinition
。例如,根据某些条件更改Bean
的作用域或属性值。实例化 Bean: 这是将
BeanDefinition
转换为实际的Bean
实例的过程。依赖注入: 在这一步,
Spring
框架会按照BeanDefinition
的描述为bean
实例注入所需的依赖。Bean 初始化: 在所有依赖都注入后,特定的初始化方法(如通过
@PostConstruct
指定的)将会被调用,完成Bean
的最后设置。执行 BeanPostProcessor 的方法:
BeanPostProcessor
提供了拦截的能力,允许在Bean
初始化阶段结束之前和之后进行操作。Bean 完全初始化: 在此阶段,
Bean
完全初始化并准备好被应用程序使用。
虚线解释:
执行 BeanDefinitionRegistryPostProcessor 到 执行 BeanFactoryPostProcessor 之间的虚线:
注册/修改/删除BeanDefinition
: 在执行 BeanDefinitionRegistryPostProcessor
的过程中,除了执行已定义的操作外,还提供了一个重要的扩展点,允许我们注册新的 BeanDefinition
、修改或删除已有的 BeanDefinition
。这为我们提供了一个机会在后续的 BeanFactoryPostProcessor
执行前改变或增强我们的 bean
定义。
执行 BeanFactoryPostProcessor 到 实例化 Bean 之间的虚线:
查看/修改BeanDefinition
: BeanFactoryPostProcessor
允许我们查看或修改已注册的 BeanDefinition
。这意味着在 bean
实例化之前,我们还有最后一次机会修改 bean
的定义或属性。例如,根据某些运行时环境或条件更改 bean
的作用域。
2.3. 动态注册 Bean:BeanDefinitionRegistryPostProcessor 实践
假设有一个Fruit
的抽象水果类,以及两个具体的水果类:Apple
和Orange
。在最初,IOC
容器中只注册了Apple
,没有Orange
。我们将使用BeanDefinitionRegistryPostProcessor
来注册一个Orange
的实例,然后利用BeanFactoryPostProcessor
来为所有的Fruit
实例设置属性。
声明 Bean
首先,我们定义抽象类Fruit
及其属性:
Orange
类没有标注@Component
注解,Spring
的组件扫描功能默认不会为其创建bean
,这个例子中会在OrangeRegisterPostProcessor
里动态创建。
编写后置处理器
使用后置处理器来注册Orange
:
为所有的Fruit
实例设置属性:
测试运行
运行结果:
这段代码展示了如何使用BeanDefinitionRegistryPostProcessor
来动态地注册beans
和为其设置属性。
3. 三种后置处理器的对比
4. 总结与洞见
4.1. BeanFactoryPostProcessor 与 BeanPostProcessor 的差异
BeanFactoryPostProcessor
和 BeanPostProcessor
都是 Spring
框架中为了增强容器的处理能力而提供的扩展点。它们都可以对 Bean
进行定制化处理,但它们的关注点和应用时机不同。
BeanFactoryPostProcessor:
功能: 允许我们在
Spring
容器实例化任何bean
之前读取bean
的定义(bean
的元数据)并进行修改。作用时机: 它会在
BeanFactory
的标准初始化之后被调用,此时,所有的bean
定义已经被加载到容器中,但还没有实例化任何bean
。此时我们可以添加、修改或移除某些bean
的定义。常见应用: 动态修改
bean
的属性、改变bean
的作用域、动态注册新的bean
等。示例接口方法:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
;
BeanPostProcessor:
功能: 允许我们在
Spring
容器实例化bean
之后对bean
进行处理,提供了一种机会在bean
的初始化前后插入我们的自定义逻辑。作用时机: 它在
bean
的生命周期中的两个时间点被调用,即在自定义初始化方法(如@PostConstruct
,init-method
)之前和之后。常见应用: 对特定的
bean
实例进行一些额外处理,如进行某种代理、修改bean
的状态等。示例接口方法:
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
; 和Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
;
总结:
BeanFactoryPostProcessor
主要关注于整个容器的配置,允许我们修改bean
的定义或元数据。它是容器级别的。BeanPostProcessor
主要关注于bean
的实例,允许我们在初始化前后对bean
实例进行操作。它是bean
级别的。
4.2. BeanFactoryPostProcessor 与 BeanDefinitionRegistryPostProcessor 的关系
BeanFactoryPostProcessor
和 BeanDefinitionRegistryPostProcessor
都是 Spring
中提供的两个重要的扩展点,它们都允许我们在 Spring
容器启动过程中对 Bean
的定义进行定制处理。但它们的应用时机和功能上存在一些不同。
BeanFactoryPostProcessor:
功能: 允许我们在
Spring
容器实例化任何bean
之前读取bean
的定义 (BeanDefinition
) 并进行修改。作用时机: 在所有的
bean
定义都被加载、但bean
实例还未创建的时候执行。常见应用: 修改已加载到容器中的
bean
定义的属性,例如更改某个bean
的作用域、属性值等。主要方法:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
;
BeanDefinitionRegistryPostProcessor:
功能: 扩展了
BeanFactoryPostProcessor
,提供了一个新的方法来修改应用程序的上下文的bean
定义。此外,还可以动态注册新的bean
定义。作用时机: 它也是在所有
bean
定义被加载后执行,但在BeanFactoryPostProcessor
之前。常见应用: 动态注册新的
bean
定义、修改或移除已有的bean
定义。主要方法:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException
;
总结:
BeanFactoryPostProcessor
主要是用来修改已经定义的bean
定义,而不是注册新的bean
。BeanDefinitionRegistryPostProcessor
是BeanFactoryPostProcessor
的扩展,并提供了额外的能力来动态地注册、修改、移除bean
定义。
在 Spring
容器的启动过程中,首先执行的是 BeanDefinitionRegistryPostProcessor
的方法,之后才是 BeanFactoryPostProcessor
的方法。
欢迎一键三连~
有问题请留言,大家一起探讨学习
----------------------Talk is cheap, show me the code-----------------------
版权声明: 本文为 InfoQ 作者【砖业洋__】的原创文章。
原文链接:【http://xie.infoq.cn/article/459c1173dcb73ba9487c8495a】。文章转载请联系作者。
评论