BeanDefinitionRegistryPostProcessor
- BeanDefinitionRegistryPostProcessor
- 一、基本信息
- 二、接口描述
- 三、接口源码
- 四、主要功能
- 五、最佳实践
- 六、时序图
- 七、源码分析
- 八、注意事项
- 九、总结
- 最佳实践总结
- 源码分析总结
一、基本信息
✒️ 作者 - Lex 📝 博客 - 我的CSDN 📚 文章目录 - 所有文章 🔗 源码地址 - BeanDefinitionRegistryPostProcessor源码
二、接口描述
BeanDefinitionRegistryPostProcessor
是 Spring 框架中的一个接口,它用于在 Spring 容器的标准初始化过程中允许我们修改应用程序上下文的内部 bean 定义。它继承自 BeanFactoryPostProcessor
接口。与 BeanFactoryPostProcessor
不同的是,它还提供了对 BeanDefinitionRegistry
的访问,这使得我们能够在运行时注册新的 beans 或修改现有的 bean 定义。
三、接口源码
InstantiationAwareBeanPostProcessor
是 Spring 框架自 3.0.1 版本开始引入的一个核心接口。最核心的方法是 postProcessBeanDefinitionRegistry
,它允许我们在运行时注册新的 beans 或修改现有的 bean 定义。
/**
* 相对于标准的 {@link BeanFactoryPostProcessor} SPI 的扩展,
* 允许在常规 BeanFactoryPostProcessor 检测启动之前 注册更多的 bean 定义。
* 特别地,BeanDefinitionRegistryPostProcessor 可以注册进一步的 bean 定义,
* 这些定义可能会进一步定义 BeanFactoryPostProcessor 实例。
*
* 作者:Juergen Hoeller
* 自版本:3.0.1 起
* 参见:org.springframework.context.annotation.ConfigurationClassPostProcessor
*/
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* 在其标准初始化之后,修改应用上下文的内部 bean 定义注册表。
* 此时,所有常规的 bean 定义都已经被加载,但还没有 bean 被实例化。
* 这允许在下一后处理阶段开始之前,添加更多的 bean 定义。
*
* @param registry 应用上下文使用的 bean 定义注册表
* @throws org.springframework.beans.BeansException 如果发生错误
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
四、主要功能
注册新的 Bean 定义
- 该接口提供了一个机制,允许在 Spring 容器完成其标准初始化(即加载所有 bean 定义)之后,但在任何 bean 实例化之前,动态注册新的 bean 定义。
修改现有的 Bean 定义
- 除了能够添加新的 bean 定义,
BeanDefinitionRegistryPostProcessor
还可以修改已经注册的 bean 定义。例如,它可以修改 bean 的属性值、构造函数参数或其它设置。
控制 BeanFactoryPostProcessor
的执行顺序
- 因为
BeanDefinitionRegistryPostProcessor
是BeanFactoryPostProcessor
的子接口,它的实现还可以控制BeanFactoryPostProcessor
的执行顺序。这是因为在 Spring 容器启动时,所有的BeanDefinitionRegistryPostProcessor
beans 首先会被实例化和调用,然后才是其他的BeanFactoryPostProcessor
beans。
基于条件的 Bean 注册
- 可以利用
BeanDefinitionRegistryPostProcessor
来基于特定的运行时条件(例如类路径上是否存在某个特定的类)来决定是否注册某个 bean。
扩展点以实现高级配置
- 对于复杂的应用或框架,这个接口提供了一个扩展点,可以在初始化过程中进行更高级的配置,如加载外部的配置或执行特殊的验证逻辑。
五、最佳实践
首先来看看启动类入口,上下文环境使用AnnotationConfigApplicationContext
(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration
组件类。然后我们从AnnotationConfigApplicationContext
中获取MySimpleBean
并调用show
方法。
public class BeanDefinitionRegistryPostProcessorApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
MySimpleBean mySimpleBean1 = context.getBean(MySimpleBean.class);
mySimpleBean1.show();
}
}
这里使用@Bean
注解,为了确保 MyBeanDefinitionRegistryPostProcessor
被 Spring 容器执行,我们需要将它注册为一个 bean,该后处理器可以新增一个BeanDefinition
。
@Configuration
public class MyConfiguration {
@Bean
public static MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor(){
return new MyBeanDefinitionRegistryPostProcessor();
}
}
在我自定义的postProcessBeanDefinitionRegistry
方法中,创建了一个新的 RootBeanDefinition
对象,该对象代表 MySimpleBean
类。然后,使用了 registry
的 registerBeanDefinition
方法来注册这个新的 bean 定义,并为它指定了名称 "mySimpleBean"
。
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("开始新增Bean定义");
// 创建一个新的 BeanDefinition 对象
BeanDefinition beanDefinition = new RootBeanDefinition(MySimpleBean.class);
// 使用 registry 来注册这个新的 bean 定义
registry.registerBeanDefinition("mySimpleBean", beanDefinition);
System.out.println("完成新增Bean定义");
}
}
要被动态注册的 Bean
public class MySimpleBean {
public void show() {
System.out.println("MySimpleBean instance: " + this);
}
}
运行结果发现,MySimpleBean
实例已成功创建,并打印了它的实例信息,这证明了 BeanDefinitionRegistryPostProcessor
成功地在运行时动态注册了这个 bean
开始新增Bean定义
完成新增Bean定义
MySimpleBean instance: com.xcs.spring.config.MySimpleBean@7e5afaa6
六、时序图
sequenceDiagram
Title: BeanFactoryPostProcessor时序图
participant BeanDefinitionRegistryPostProcessorApplication
participant AnnotationConfigApplicationContext
participant AbstractApplicationContext
participant PostProcessorRegistrationDelegate
participant MyBeanDefinitionRegistryPostProcessor
participant BeanDefinitionRegistry
BeanDefinitionRegistryPostProcessorApplication->>AnnotationConfigApplicationContext:AnnotationConfigApplicationContext(...)启动上下文
AnnotationConfigApplicationContext->>AbstractApplicationContext:refresh()
AbstractApplicationContext->>AbstractApplicationContext:invokeBeanFactoryPostProcessors(...)触发整个BeanFactoryPostProcessor调用的流程
AbstractApplicationContext->>PostProcessorRegistrationDelegate:invokeBeanFactoryPostProcessors(...)确保正确的顺序触发BeanDefinitionRegistryPostProcessor调用的流程
PostProcessorRegistrationDelegate->>PostProcessorRegistrationDelegate:invokeBeanDefinitionRegistryPostProcessors(...)最终对BeanDefinitionRegistryPostProcessor接口回调
PostProcessorRegistrationDelegate->>MyBeanDefinitionRegistryPostProcessor:postProcessBeanDefinitionRegistry(...)执行自定义的逻辑
MyBeanDefinitionRegistryPostProcessor-->>BeanDefinitionRegistry:通过新增bean定义
BeanDefinitionRegistry-->>MyBeanDefinitionRegistryPostProcessor:新增已完成
PostProcessorRegistrationDelegate-->>AbstractApplicationContext: 调用Bean工厂后置处理器完成
AnnotationConfigApplicationContext->>BeanDefinitionRegistryPostProcessorApplication:初始化完成
七、源码分析
首先来看看启动类入口,上下文环境使用AnnotationConfigApplicationContext
(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个MyConfiguration
组件类。然后我们从AnnotationConfigApplicationContext
中获取MySimpleBean
并调用show
方法。
public class BeanDefinitionRegistryPostProcessorApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
MySimpleBean mySimpleBean1 = context.getBean(MySimpleBean.class);
mySimpleBean1.show();
}
}
在org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext
构造函数中,执行了三个步骤,我们重点关注refresh()
方法。
public AnnotationConfigApplicationContext(Class... componentClasses) {
this();
register(componentClasses);
refresh();
}
在org.springframework.context.support.AbstractApplicationContext#refresh
方法中,我们重点关注一下finishBeanFactoryInitialization(beanFactory)
这方法会对实例化所有剩余非懒加载的单列Bean对象,其他方法不是本次源码阅读的重点暂时忽略。
@Override
public void refresh() throws BeansException, IllegalStateException {
// ... [代码部分省略以简化]
// 调用在上下文中注册为bean的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// ... [代码部分省略以简化]
}
在org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors
方法中,又委托了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
进行调用。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// ... [代码部分省略以简化]
}
在org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
方法中,主要是对BeanDefinitionRegistryPostProcessor
,BeanFactoryPostProcessor
这两个接口的实现类进行回调,至于为什么这个方法里面代码很长呢?其实这个方法就做了一个事就是对处理器的执行顺序在做处理。比如说要先对实现了PriorityOrdered.class
类回调,在对实现了Ordered.class
类回调,最后才是对没有实现任何优先级的处理器进行回调。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {
// 先调用 BeanDefinitionRegistryPostProcessors (如果有的话)
Set processedBeans = new HashSet();
// 判断 beanFactory 是否为 BeanDefinitionRegistry 的实例
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List regularPostProcessors = new ArrayList();
List registryProcessors = new ArrayList();
// 遍历所有的后处理器,按类型分类
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// 这里不初始化 FactoryBeans,为了让 bean 工厂的后处理器可以应用到它们
List currentRegistryProcessors = new ArrayList();
// 首先,调用实现了 PriorityOrdered 的 BeanDefinitionRegistryPostProcessors
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
// 接下来,调用实现了 Ordered 的 BeanDefinitionRegistryPostProcessors
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
// 最后,调用所有其他的 BeanDefinitionRegistryPostProcessors,直到没有更多的后处理器出现
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
// 现在,调用到目前为止处理过的所有处理器的 postProcessBeanFactory 回调
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// 调用在上下文实例中注册的工厂处理器
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// ... [代码部分省略以简化]
}
下面是我画的一个关于BeanDefinitionRegistryPostProcessor
排序回调过程时序图大家可以参考一下。
sequenceDiagram
Title: BeanDefinitionRegistryPostProcessor回调排序时序图
participant Init as invokeBeanFactoryPostProcessors
participant BDRPP_PO as BDRPP(PriorityOrdered)
participant BDRPP_O as BDRPP(Ordered)
participant BDRPP as 其余的BDRPP
Init->>BDRPP_PO: 回调
BDRPP_PO-->>Init: 完成
Init->>BDRPP_O: 回调
BDRPP_O-->>Init: 完成
Init->>BDRPP: 回调
BDRPP-->>Init: 完成
Note right of BDRPP: 提示:
Note right of BDRPP: BDRPP = BeanFactoryPostProcessor
在org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
方法中,循环调用了实现BeanDefinitionRegistryPostProcessor
接口中的postProcessBeanDefinitionRegistry(registry)
方法
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection