Spring Boot 扩展之BeanDefinitionRegistryPostProcessor接口源码解析

简介: Spring Boot 扩展之BeanDefinitionRegistryPostProcessor接口源码解析

概述


Spring中的每个bean的创建是依赖一个对应的BeanDefintion实例,该实例保存了bean对象创建必要的信息,比如bean的class类型,是否是抽象类、属性信息等。BeanDefinitionRegistry是一个接口,bean定义信息的注册中心,用于注册、删除、管理BeanDefintion

如果外部想要添加Bean的定义信息,创建新的Bean, 怎么办? 当然是可以通过Spring提供的扩展接口BeanDefinitionRegistryPostProcessor实现,比较典型的一个案例是mybatis-spring,就是通过实现该接口,添加mybatis相关的bean。

所以,BeanDefinitionRegistryPostProcessor就是bean定义注册中心的后置处理器,允许我们修改拓展bean定义信息的注册中心,在所有bean定义信息将要被加载,bean实例还未创建的时候执行。


使用实例


  1. 新建类实现BeanDefinitionRegistryPostProcessor
@Component
public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        log.info("******************** TestBeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry ****************");
        log.info("******************** bean的数量:[{}] ****************", beanDefinitionRegistry.getBeanDefinitionCount());
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        propertyValues.addPropertyValue("username", "alvin");
        propertyValues.addPropertyValue("age", 12);
        // 注册bean信息
        beanDefinitionRegistry.registerBeanDefinition("beanDefineDemo", beanDefinition);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        log.info("******************** TestBeanDefinitionRegistryPostProcessor#postProcessBeanFactory ****************");
        log.info("******************** bean的数量:[{}] ****************", configurableListableBeanFactory.getBeanDefinitionCount());
    }
}
  1. 实现类需要添加@Component注解

1671090132366.jpg

  1. 验证注入的bean

1671090139335.jpg

1671090145887.jpg


源码解析


可以通过debug的方式,在postProcessBeanDefinitionRegistry方法中打上断点,查看Deubbger中的Frames记录,快速定位代码的调用链路。


接口的定义说明


/**
 * 扩展到标准的{@link BeanFactoryPostProcessor} SPI
 * 允许在常规BeanFactoryPostProcessor检测开始之前注册更多的bean定义。
 * 特别是,BeanDefinitionRegistryPostProcessor可以注册更多的bean定义,
 * 这些定义反过来又定义了BeanFactoryPostProcessor实例。
 * 
 * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
 * the registration of further bean definitions <i>before</i> regular
 * BeanFactoryPostProcessor detection kicks in. In particular,
 * BeanDefinitionRegistryPostProcessor may register further bean definitions
 * which in turn define BeanFactoryPostProcessor instances.
 *
 * @author Juergen Hoeller
 * @since 3.0.1
 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor
 */
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
  /**
     * 在标准初始化之后修改应用程序上下文的内部bean定义注册表。所有常规bean定义都已加载,
     * 但还没有实例化bean。这允许在进入下一个后处理阶段之前添加更多的bean定义。
     * 
   * Modify the application context's internal bean definition registry after its
   * standard initialization. All regular bean definitions will have been loaded,
   * but no beans will have been instantiated yet. This allows for adding further
   * bean definitions before the next post-processing phase kicks in.
   * @param registry the bean definition registry used by the application context
   * @throws org.springframework.beans.BeansException in case of errors
   */
  void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

通过翻译看,此接口目的是为了提供给开发者向容器中注册更多的BeanDefinition, 实现动态注册bean的目的。


执行流程


image.png

以上是整个执行的序列图,关键点是AbstractApplicationContext#refresh()


1. AbstractApplicationContext#refresh()


public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
      // Prepare this context for refreshing.
            // 刷新上下文的准备阶段,跳过
      prepareRefresh();
      // Tell the subclass to refresh the internal bean factory.
      // 创建beanFacotry工厂
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // Prepare the bean factory for use in this context.
            // beanFactory准备工作, 跳过
      prepareBeanFactory(beanFactory);
      try {
        // Allows post-processing of the bean factory in context subclasses.
        postProcessBeanFactory(beanFactory);
        StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
        // Invoke factory processors registered as beans in the context.
        // 调用注册的BeanFactoryPostProcessors对象
                invokeBeanFactoryPostProcessors(beanFactory);
    }
  }


2. AbstractApplicationContext#invokeBeanFactoryPostProcessors


protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 注册的核心代码, beanFactory代表当前的容器, 第二个参数为内置的参数处理器
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
      .....
}


3. PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors


public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    // WARNING: Although it may appear that the body of this method can be easily
    // refactored to avoid the use of multiple loops and multiple lists, the use
    // of multiple lists and multiple passes over the names of processors is
    // intentional. We must ensure that we honor the contracts for PriorityOrdered
    // and Ordered processors. Specifically, we must NOT cause processors to be
    // instantiated (via getBean() invocations) or registered in the ApplicationContext
    // in the wrong order.
    //
    // Before submitting a pull request (PR) to change this method, please review the
    // list of all declined PRs involving changes to PostProcessorRegistrationDelegate
    // to ensure that your proposal does not result in a breaking change:
    // https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        // 如果存在BeanDefinitionRegistryPostProcessors,那么就会首先调用。
    Set<String> processedBeans = new HashSet<>();
    if (beanFactory instanceof BeanDefinitionRegistry) {
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      // 常规的BeanFactory后置处理器集合
            List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
      // Bean定义注册的后置处理器
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
            // 遍历容器优先内置的后置处理器
      for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
        // 判断是否为Bean定义注册的后置处理器
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
          BeanDefinitionRegistryPostProcessor registryProcessor =
              (BeanDefinitionRegistryPostProcessor) postProcessor;
                    // 直接调用postProcessBeanDefinitionRegistry方法
          registryProcessor.postProcessBeanDefinitionRegistry(registry);
          registryProcessors.add(registryProcessor);
        }
        else {
          regularPostProcessors.add(postProcessor);
        }
      }
      // Do not initialize FactoryBeans here: We need to leave all regular beans
      // uninitialized to let the bean factory post-processors apply to them!
      // Separate between BeanDefinitionRegistryPostProcessors that implement
      // PriorityOrdered, Ordered, and the rest.
            // 定义外部实现了BeanDefinitionRegistryPostProcessor扩展的集合
      List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
      // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
      // 首先,调用实现PriorityOrdered的 BeanDefinitionRegistryPostProcessor。
            // 此处获取的postProcessorNames必须是已经进行注册过的BeanDefinition。
            // 第一次我们无法找到我们写的BeanDefinitionRegistryPostProcessor,是因为它本身并未注册到bean定义注册中心。
            // 但是会发现有ConfigurationClassPostProcessor,它会帮我们写的PostProcessor注册到bean定义注册中心。
            String[] postProcessorNames =
          beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
        // 判断BeanDefinitionRegistryPostProcessor是否实现了PriorityOrdered接口
                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();
      // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
      // 再次获取BeanDefinitionRegistryPostProcessor后置处理器,此时可以看到我们写的后置处理器,
            // 那是因为我们写的后置处理器bean定义经过ConfigurationClassPostProcessor注册
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
        // 判断是否实现了Ordered接口
                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();
      // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
      // 最后执行没有实现Orderd接口的后置处理器
            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();
      }
      // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
      // 因为
            invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
      invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    }
    else {
      // Invoke factory processors registered with the context instance.
      invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }
        // 后面的内容是执行BeanFactoryPostProcessor的后置处理器,后面再说
        .....
  }

小结:

  • 自己定义的后置处理器想要生效,前提是必须本身要被注册到BeanDefinitionRegistry注册中心,这也是为什么我们需要加@Component注解。
  • 那我们添加@Component注解的后置处理器在上面时候注册到BeanDefinitionRegistry注册中心呢? 实在ConfigurationClassPostProcessor中动态注册的,这也是为什么第一次获取BeanDefinitionRegistryPostProcessor相关的bean name时候,没有找到我们写的,因为我们写的还没有注册到BeanDefinitionRegistry注册中心。
  • BeanDefinitionRegistryPostProcessor的执行顺序是,实现了@PriorityOrdered优先执行,其次是实现了@Ordered,最后是没有实现的后置处理器。


内置的BeanDefinitionRegistryPostProcessor


SpringBoot比较重要的内置的BeanDefinitionRegistryPostProcessor后置处理器是ConfigurationClassPostProcessor,它主要是帮我们完成注解扫描和类定义注册,然后再由BeanFactory完成实例化以及初始化逻辑,那它本身是在什么时候注册到注册中心的呢,内部原理又是什么样呢?


参考


juejin.cn/post/684490…

blog.csdn.net/qq_42154259…

www.cnblogs.com/warrior4236…

cloud.tencent.com/developer/a…

目录
相关文章
|
5天前
|
XML 安全 前端开发
Spring Security 重点解析(下)
Spring Security 重点解析
17 1
|
4天前
|
移动开发 供应链 Java
企业级智能制造MES系统源码,技术架构:springboot + vue-element-plus-admin
企业级智能制造MES系统源码,技术架构:springboot + vue-element-plus-admin。 企业级云MES全套源码,支持app、小程序、H5、台后管理。 生产调度:MES系统可以根据生产订单和资源状况,自动计算生产计划和调度,从而优化生产线的运作。
企业级智能制造MES系统源码,技术架构:springboot + vue-element-plus-admin
|
4天前
|
XML JavaScript 前端开发
springboot配合Freemark模板生成word,前台vue接收并下载【步骤详解并奉上源码】
springboot配合Freemark模板生成word,前台vue接收并下载【步骤详解并奉上源码】
|
5天前
|
缓存 前端开发 Java
【框架】Spring 框架重点解析
【框架】Spring 框架重点解析
20 0
|
5天前
|
安全 NoSQL Java
Spring Security 重点解析(上)
Spring Security 重点解析
16 1
|
5天前
|
监控 Java 应用服务中间件
Spring Boot 源码面试知识点
【5月更文挑战第12天】Spring Boot 是一个强大且广泛使用的框架,旨在简化 Spring 应用程序的开发过程。深入了解 Spring Boot 的源码,有助于开发者更好地使用和定制这个框架。以下是一些关键的知识点:
25 6
|
2天前
|
监控 安全 NoSQL
采用java+springboot+vue.js+uniapp开发的一整套云MES系统源码 MES制造管理系统源码
MES系统是一套具备实时管理能力,建立一个全面的、集成的、稳定的制造物流质量控制体系;对生产线、工艺、人员、品质、效率等多方位的监控、分析、改进,满足精细化、透明化、自动化、实时化、数据化、一体化管理,实现企业柔性化制造管理。
21 3
|
3天前
|
前端开发 Java
audio案例(1),2024年最新springboot项目源码
audio案例(1),2024年最新springboot项目源码
|
3天前
|
数据采集 监控 安全
java数字工厂MES系统全套源码Java+idea+springboot专业为企业提供智能制造MES解决方案
"MES" 指的是制造执行系统(Manufacturing Execution System)。MES在制造业中扮演着至关重要的角色,它是位于企业资源计划(ERP)系统和车间控制系统之间的系统,用于实时收集、管理、分析和报告与制造过程相关的数据。
10 0
|
3天前
|
Linux 网络安全 Windows
网络安全笔记-day8,DHCP部署_dhcp搭建部署,源码解析
网络安全笔记-day8,DHCP部署_dhcp搭建部署,源码解析

热门文章

最新文章

推荐镜像

更多