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;

}

四、主要功能

  1. 注册新的 Bean 定义

    • 该接口提供了一个机制,允许在 Spring 容器完成其标准初始化(即加载所有 bean 定义)之后,但在任何 bean 实例化之前,动态注册新的 bean 定义。
  2. 修改现有的 Bean 定义

    • 除了能够添加新的 bean 定义,BeanDefinitionRegistryPostProcessor 还可以修改已经注册的 bean 定义。例如,它可以修改 bean 的属性值、构造函数参数或其它设置。
  3. 控制 BeanFactoryPostProcessor 的执行顺序

    • 因为 BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor 的子接口,它的实现还可以控制 BeanFactoryPostProcessor 的执行顺序。这是因为在 Spring 容器启动时,所有的 BeanDefinitionRegistryPostProcessor beans 首先会被实例化和调用,然后才是其他的 BeanFactoryPostProcessor beans。
  4. 基于条件的 Bean 注册

    • 可以利用 BeanDefinitionRegistryPostProcessor 来基于特定的运行时条件(例如类路径上是否存在某个特定的类)来决定是否注册某个 bean。
  5. 扩展点以实现高级配置

    • 对于复杂的应用或框架,这个接口提供了一个扩展点,可以在初始化过程中进行更高级的配置,如加载外部的配置或执行特殊的验证逻辑。

五、最佳实践

首先来看看启动类入口,上下文环境使用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 类。然后,使用了 registryregisterBeanDefinition 方法来注册这个新的 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

六、时序图

BeanDefinitionRegistryPostProcessorApplication AnnotationConfigApplicationContext AbstractApplicationContext PostProcessorRegistrationDelegate MyBeanDefinitionRegistryPostProcessor BeanDefinitionRegistry AnnotationConfigApplicationContext(...) 启动上下文 refresh() invokeBeanFactoryPostProcessors(...) 触发整个BeanFactoryPostProcessor调用的流程 invokeBeanFactoryPostProcessors(...) 确保正确的顺序触发BeanDefinitionRegistryPostProcessor调用的流程 invokeBeanDefinitionRegistryPostProcessors(...) 最终对BeanDefinitionRegistryPostProcessor接口回调 postProcessBeanDefinitionRegistry(...) 执行自定义的逻辑 通过新增bean定义 新增已完成 调用Bean工厂后置处理器完成 初始化完成 BeanDefinitionRegistryPostProcessorApplication AnnotationConfigApplicationContext AbstractApplicationContext PostProcessorRegistrationDelegate MyBeanDefinitionRegistryPostProcessor BeanDefinitionRegistry BeanFactoryPostProcessor时序图

七、源码分析

首先来看看启动类入口,上下文环境使用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方法中,主要是对BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor这两个接口的实现类进行回调,至于为什么这个方法里面代码很长呢?其实这个方法就做了一个事就是对处理器的执行顺序在做处理。比如说要先对实现了PriorityOrdered.class类回调,在对实现了Ordered.class类回调,最后才是对没有实现任何优先级的处理器进行回调。

public static void invokeBeanFactoryPostProcessors(
        ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

    // 先调用 BeanDefinitionRegistryPostProcessors (如果有的话)
    Set<String> processedBeans = new HashSet<>();

    // 判断 beanFactory 是否为 BeanDefinitionRegistry 的实例
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        List<BeanDefinitionRegistryPostProcessor> 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<BeanDefinitionRegistryPostProcessor> 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排序回调过程时序图大家可以参考一下。

invokeBeanFactoryPostProcessors BDRPP(PriorityOrdered) BDRPP(Ordered) 其余的BDRPP 回调 完成 回调 完成 回调 完成 提示: BDRPP = BeanFactoryPostProcessor invokeBeanFactoryPostProcessors BDRPP(PriorityOrdered) BDRPP(Ordered) 其余的BDRPP BeanDefinitionRegistryPostProcessor回调排序时序图

org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors方法中,循环调用了实现BeanDefinitionRegistryPostProcessor接口中的postProcessBeanDefinitionRegistry(registry)方法

private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
        StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
            .tag("postProcessor", postProcessor::toString);
        postProcessor.postProcessBeanDefinitionRegistry(registry);
        postProcessBeanDefRegistry.end();
    }
}

最后执行到我们自定义的逻辑中,我们在postProcessBeanDefinitionRegistry方法中注册了一个新的 bean 定义,在实际应用中,我们可以在 postProcessBeanDefinitionRegistry 方法内部执行更复杂的操作,例如修改 bean 的属性、对Bean对象进行代理做功能增强处理、更改它们的作用域或添加新的 bean 定义等。

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定义");
    }
}

八、注意事项

  1. 调用顺序

    • BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor 有更高的优先级。这意味着 BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry 方法会在任何 BeanFactoryPostProcessorpostProcessBeanFactory 方法之前被调用。如果我们在Spring中有多个 BeanDefinitionRegistryPostProcessor,它们之间的执行顺序可能会受到 OrderedPriorityOrdered 接口的影响,所以要确保正确地实现这些接口以确保预期的执行顺序。
  2. 过早实例化

    • 一个常见的陷阱是,定义在 @Configuration 类中返回 BeanDefinitionRegistryPostProcessor 的非静态 @Bean 方法可能导致配置类过早实例化。为避免这一问题,这种方法应该被声明为 static。在本次最近实践中我们也是用到了static来修饰我们的MyBeanDefinitionRegistryPostProcessor
  3. 不要过度使用

    • 虽然 BeanDefinitionRegistryPostProcessor 提供了强大的功能,但不应该在不需要修改或动态添加 Bean 定义的情况下滥用它,除非我们是框架我们。在我们绝大部分业务系统中,我觉得我们其实只要使用@Component@Service@Repository@Controller@Configuration 注解应该足够使用。

九、总结

最佳实践总结
  1. 应用启动

    • 启动类 BeanDefinitionRegistryPostProcessorApplication 通过 AnnotationConfigApplicationContext 初始化 Spring 容器,并加载了 MyConfiguration 类作为配置。
  2. 配置类定义

    • MyConfiguration 类中,我们通过 @Bean 注解定义了一个静态方法,该方法返回一个 MyBeanDefinitionRegistryPostProcessor 对象,确保它在 Spring 容器初始化时被执行。
  3. 动态注册

    • 在我们自定义的 MyBeanDefinitionRegistryPostProcessor 实现中,我们重写了 postProcessBeanDefinitionRegistry 方法。在这个方法里,我们创建了一个新的 RootBeanDefinition 对象来代表 MySimpleBean 类,并通过 registryregisterBeanDefinition 方法注册了这个新的 bean 定义,为它指定了名为 "mySimpleBean" 的名称。
  4. 目标 Bean

    • MySimpleBean 是一个简单的 bean 类,它的 show 方法用于输出它自身的实例信息。
  5. 验证动态注册

    • 当运行 BeanDefinitionRegistryPostProcessorApplication 时,可以观察到控制台首先打印了 “开始新增Bean定义” 和 “完成新增Bean定义”,说明 postProcessBeanDefinitionRegistry 方法被正确执行。紧接着,MySimpleBean 的实例被创建并打印了它的实例信息,证明 BeanDefinitionRegistryPostProcessor 成功地在运行时动态注册了这个 bean。
源码分析总结
  1. 应用启动

    • 通过 AnnotationConfigApplicationContext 来初始化 Spring 容器并加载 MyConfiguration 配置类。随后从该上下文中获取 MySimpleBean 并调用其 show 方法。
  2. Spring容器的刷新

    • AnnotationConfigApplicationContext 的构造函数调用了 refresh() 方法,负责启动 Spring 容器的初始化流程。
  3. 执行Bean工厂的后处理器

    • refresh() 方法中,调用了 invokeBeanFactoryPostProcessors(beanFactory) 方法,负责执行所有注册的 BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor 接口实现。
  4. 按优先级执行回调

    • Spring 按照不同的优先级(如 PriorityOrderedOrdered)对 BeanDefinitionRegistryPostProcessor 进行排序并回调。这确保了回调的执行顺序。
  5. 动态注册Bean定义

    • 在我们自定义的 MyBeanDefinitionRegistryPostProcessor 中,我们重写了 postProcessBeanDefinitionRegistry 方法。在该方法内部,我们动态地创建了 MySimpleBean 的定义,并将其注册到了容器中。
  6. 执行结果

    • MySimpleBean 成功被动态注册到 Spring 容器中,从而能够在应用启动时被检索并使用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值