Spring5源码 - 04 invokeBeanFactoryPostProcessors 源码解读_1

简介: Spring5源码 - 04 invokeBeanFactoryPostProcessors 源码解读_1

20200914143739548.png

Pre


接上文 Spring5源码 - 03 普通对象对应的BeanDefinition是如何存入DefaultListableBeanFactory#beanDefinitionMap 源码分析


refresh()

这里我们只粗略的看一下其中的逻辑,真的很复杂

@Override
  public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
      // Prepare this context for refreshing.  1:准备刷新上下文环境 
      prepareRefresh();
      // Tell the subclass to refresh the internal bean factory. 2:获取告诉子类初始化Bean工厂
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // Prepare the bean factory for use in this context. 3:对bean工厂进行填充属性
      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. 调用bean工厂的后置处理器.
        invokeBeanFactoryPostProcessors(beanFactory);
        // Register bean processors that intercept bean creation.  调用bean的后置处理器
        registerBeanPostProcessors(beanFactory);
        beanPostProcess.end();
        // Initialize message source for this context.  初始化国际化资源处理器.  
        initMessageSource();
        // Initialize event multicaster for this context. 创建事件多播器
        initApplicationEventMulticaster();
        // Initialize other special beans in specific context subclasses.  这个方法同样也是留给子类实现的    springboot也是从这个方法进行启动tomat的.
        onRefresh();
        // Check for listener beans and register them.  把我们的事件监听器注册到多播器上
        registerListeners();
        // Instantiate all remaining (non-lazy-init) singletons.  实例化我们剩余的单实例bean.
        finishBeanFactoryInitialization(beanFactory);
        // Last step: publish corresponding event.  最后容器刷新 发布刷新事件(Spring cloud也是从这里启动的)
        finishRefresh();
      }
      catch (BeansException ex) {
        if (logger.isWarnEnabled()) {
          logger.warn("Exception encountered during context initialization - " +
              "cancelling refresh attempt: " + ex);
        }
        // Destroy already created singletons to avoid dangling resources.
        destroyBeans();
        // Reset 'active' flag.
        cancelRefresh(ex);
        // Propagate exception to caller.
        throw ex;
      }
      finally {
        // Reset common introspection caches in Spring's core, since we
        // might not ever need metadata for singleton beans anymore...
        resetCommonCaches();
        contextRefresh.end();
      }
    }
  }


Spring的设计


我们接着来看 spring 是在哪一个方法调用中完成扫描的 即什么时候初始化BeanDefinition, 并且把这个BeanDefinition放到bdMap集合中。

通过debug分析可以得出


20200916143723729.png

invokeBeanFactoryPostProcessors(beanFactory);


主要工作


执行所有的需要被执行的BeanFactoryPostProcessor

1.1 执行Spring内置的BeanFactoryPostProcessor (完成Bean的扫描) 【其实就是ConfigurationClassPostProcessor】

1.2 执行开发人员提供的BeanFactoryPostProcessor


2020091614411471.png

源码验证


再细说一下主要的设计思想


看方法名 invokeBeanFactoryPostProcessors 也能猜到 主要是执行 BeanFactoryPostProcessors


既然是 BeanFactoryPostProcessors , 那就说明有很多 BeanFactoryPostProcessor


BeanFactoryPostProcessor是个接口,spring实现了一部分,当然开发人员也可以实现BeanFactoryPostProcessor接口。


那Spring该如何决定这些接口实现类的先后顺序呢? 这就是Spring IOC 核心的地方。


先说说Spring的几个比较核心的子类和实现类

20200916155140935.png


主要干的两个活

  1. 执行直接实现了BeanFactoryPostProcessor
  2. 执行实现了BeanDefinitionRegistryPostProcessor


举个例子 ,假设我们有个自己的类 ,实现了 子类BeanDefinitionRegistryPostProcessor接口

ArtisanTest02 implements BeanDefinitionRegistryPostProcessor


那么你不仅要把BeanDefinitionRegistryPostProcessor的接口实现,还要实现其父类BeanFactoryPostProcessor接口的方法,那么在调用invokeBeanFactoryPostProcessors的时候 ,这两个方法都会被执行 。


假设还有一个类 ,ArtisanTest03 实现了 BeanFactoryPostProcessor 接口

ArtisanTest03  implements BeanFactoryPostProcessor

20200916160514922.png

来运行看下效果


20200916162904322.png


20200916162721841.png

20200916162738252.png

20200916162822548.png


相关文章
|
1月前
|
XML 缓存 Java
Spring源码之 Bean 的循环依赖
循环依赖是 Spring 中经典问题之一,那么到底什么是循环依赖?简单说就是对象之间相互引用, 如下图所示: 代码层面上很好理解,在 bean 创建过程中 class A 和 class B 又经历了怎样的过程呢? 可以看出形成了一个闭环,如果想解决这个问题,那么在属性填充时要保证不二次创建 A对象 的步骤,也就是必须保证从容器中能够直接获取到 B。 一、复现循环依赖问题 Spring 中默认允许循环依赖的存在,但在 Spring Boot 2.6.x 版本开始默认禁用了循环依赖 1. 基于xml复现循环依赖 定义实体 Bean java复制代码public class A {
|
2月前
|
监控 数据可视化 关系型数据库
微服务架构+Java+Spring Cloud +UniApp +MySql智慧工地系统源码
项目管理:项目名称、施工单位名称、项目地址、项目地址、总造价、总面积、施工准可证、开工日期、计划竣工日期、项目状态等。
308 6
|
2月前
Spring5源码(45)-@Transactional声明式事物(三)事物创建
Spring5源码(45)-@Transactional声明式事物(三)事物创建
41 0
|
2月前
|
Java 关系型数据库 数据库连接
Spring源码解析--深入Spring事务原理
本文将带领大家领略Spring事务的风采,Spring事务是我们在日常开发中经常会遇到的,也是各种大小面试中的高频题,希望通过本文,能让大家对Spring事务有个深入的了解,无论开发还是面试,都不会让Spring事务成为拦路虎。
35 1
|
2月前
|
Java 应用服务中间件 Spring
Spring5源码(50)-SpringMVC源码阅读环境搭建
Spring5源码(50)-SpringMVC源码阅读环境搭建
42 0
|
1月前
|
Java 测试技术 数据库连接
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
【Spring源码解读!底层原理高级进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨
|
5天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
12天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
1月前
|
Java Spring
使用spring实现邮件的发送(含测试,源码,注释)
使用spring实现邮件的发送(含测试,源码,注释)
7 0
|
1月前
|
Java Spring 容器
【Spring源码】单例创建期间进行同步可能会导致死锁?
通过这个标题我们就可以思考本次的阅读线索了,看起来可以学到不少东西。1. 旧代码的死锁是怎么产生的。2. 贡献者通过改变什么来解决本次PR的问题呢?而阅读线索2的答案也显而易见,就是上文提到的通过后台线程来创建Micrometer单例...
44 3