第五节 Starter 的加载全貌

tips:下载源码,再结合本章内容,学习整个加载过程。

上一章,我们理解了 spring.factories 的触发时机,但放在 SpringBoot 的整个加载过程来讲,只能算部分。 而这一章,将从 SpringBoot 的加载全貌,进一步理解 Starter 的加载时机。

SpringBoot 的整个启动流程是比较复杂的,代码也较多;尽量抓住核心部分进行讲解。当然也不能对所有代码逐行进行分析, 坚持二八原则。

一、SpringBoot 启动过程

对于整个 SpringBoot 应用组成,可以分为两个部分。 一部分是 SpringBoot 核心基础,另外一部分是 spring framework 框架核心。通过这两部分组合,实现 SpringBoot 的加载启动

下图展示了 SpringBoot 启动过程高层次的组件图。 本文主要围绕图片中左边部分(SpringBoot加载过程)

二、 解析关键类

Spring Boot 启动的关键代表类。 ConfigurationClassParser 在整个 bean 启动过程中起到了十分关键的作用,它也是 Starter 与 SpringBoot 建立联系的桥梁

各个类的描述

作用和描述

SpringApplication

Spring Boot 应用启动的主要入口点。它负责引导应用程序,创建并配置Spring上下文

SpringApplicationRunListeners

监听器用于在应用程序的不同启动阶段接收事件通知;例如环境准备、上下文创建和应用程序启动等

ApplicationContext

这是 Spring 框架的中心接口,代表了 Spring 容器。它管理应用程序中的bean定义、解析依赖关系等

BeanDefinition

这是Spring中的一个核心概念,代表了 Spring 容器中的一个 bean 的定义,包括它的属性、构造器参数和具体的实现类等信息

ConfigurationClassPostProcessor

特殊的 BeanFactory 后置处理器,用于处理 @Configuration 注解的类,从而读取和解析应用程序的配置。

ConfigurationClassParser

用于解析@Configuration注解的类,分析@Bean方法以及@ComponentScan、@Import等注解。是最重要的解析类。

AutoConfigurationImportSelector

实现 ImportSelector 接口,在 ConfigurationClassParser # processDeferredImportSelectors 处理 spring.factories 中的 Configuration 类,是自动装配、扩展的核心组件

SpringFactoriesLoader

自定义spi的实现,读取spring.factories中的数据

BeanFactory

Spring的一个核心接口,它提供了高级别的bean工厂能力,用于管理和创建应用程序中的bean

BeanDefinitionRegistry

是一个接口,提供了注册 BeanDefinition 以及查询 BeanDefinition 的能力

关键核心类: ConfigurationClassPostProcessor、ConfigurationClassParser、SpringFactoriesLoader、ConfigurationClassPostProcessor 等几个类;其他几个是 bean 的实例化。

下面的时序图给出了关键位置。

三、 关键时序图

通过后置处理器 ConfigurationClassPostProcessor 调用 ConfigurationClassParser 来解析配置类,包括读取配置类中的注解信息,比如 @Bean@ComponentScan@Import等,并将其转化为容器中管理的bean定义。

ConfigurationClassParser 是解析核心。

在 ConfigurationClassParser # processDeferredImportSelectors 将处理所有延迟的ImportSelectors

能够处理 spring.factories 中的 org.springframework.boot.autoconfigure.EnableAutoConfiguration ,是通过 importSelector # selectImports 返回 list 集合。而 importSelector 接口实现最重要的类则是AutoConfigurationImportSelector

四、桥梁纽带之AutoConfigurationImportSelector

org.springframework.context.annotation.ConfigurationClassParser#processDeferredImportSelectors 将是建立 spring.factories 与 Spring 容器之间的桥梁,而AutoConfigurationImportSelector 是整个自动装配的纽带。

AutoConfigurationImportSelector是Spring Boot自动配置机制的关键组成部分。

  1. 自动配置类选择: AutoConfigurationImportSelector实现了Spring Framework中的ImportSelector接口,它负责在Spring Boot应用程序启动过程中选择和激活一系列的自动配置类。
  2. 读取spring.factories: 它使用SpringFactoriesLoader来读取在类路径中的META-INF/spring.factories文件的全路径名。
  3. AutoConfigurationImportSelector通过AutoConfigurationImportFilter接口实现的实例来过滤自动配置类,确保只有符合当前应用程序上下文条件的自动配置类被包含在内。

AutoConfigurationImportSelector可以智能地应用对应的配置,从而为应用程序提供了很大的灵活性和便利。

关于 AutoConfigurationImportSelector的引入过程如下:

@SpringBootApplication > @EnableAutoConfiguration > @Import(AutoConfigurationImportSelector.class)

关于 AutoConfigurationImportSelector 类图情况

通过 AutoConfigurationImportFilter 的使用,AutoConfigurationImportSelector 可以精确地控制哪些自动配置类应被激活,以及哪些应被排除,确保了自动配置的灵活性和准确性。

实现了 DeferredImportSelector 的 接口, Spring 调用其 selectImports() 方法。其中 DeferredImportSelector 继承了 ImportSelector,DeferredImportSelector 实例的 selectImports() 方法的调用时机晚于 ImportSelector 实例, 等到 @Configuration 注解中相关的业务全部都处理完了才会调用

AutoConfigurationImportSelector: 实现 ImportSelector 接口,负责读取spring.factories文件,并将符合条件的配置类名作为候选配置返回给Spring容器。

SpringFactoriesLoader: 用于加载 spring.factories 文件中指定的工厂名。

读取过程如下所示:

五、全局解析时序图

图一、重点关注 springBoot 应用启动过程,以及 springBoot 和 ConfigurationClassParser 之间的时序。

图二、重点关注 spring.factories 的加载以及 和 AutoConfigurationImportSelector 之间的关系

图三、重点关注 ConfigurationClassParser 解析过程

特别说明:解析是一个递归过程,下面的时序图只能表示逻辑思想,不是严格的顺序。

六、本章小结

  1. SpringBoot Application 包含两个核心部分:一部分 SpringBoot, 一部分 Spring framework core
  2. 其中最核心关键的是 ConfigurationClassParser,processDeferredImportSelectors 是 Starter 与 Spring 容器核心的桥梁。

到这里,对整个 Starter 的解析过程,已经有了一个大概的理解,接下来,我们会再深入地分析自动装配过程和 ConfigurationClassParser 源码解析。


七、延伸阅读 configClasses -> BeanDefinition

上面只是解析 ConfigurationClass,将其变成 Spring容器(DefaultListableBeanFactory)中的 BeanDefinition。 还需 ConfigurationClassBeanDefinitionReader 等处理。

关键代码 org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
     ....
    do {
        parser.parse(candidates);
         ...

        // Read the model and create bean definitions based on its content
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
        }
       // 将 configClasses 变成 BeanDefinition
        this.reader.loadBeanDefinitions(configClasses);
        ...
    }
    while (!candidates.isEmpty());
    ...
}

执行之前 this.reader.loadBeanDefinitions(configClasses);

此时 DefaultListableBeanFactory 中数量为 10

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);

执行以后。 BeanDefinition 从 10 变成 162。将所有相关 configuration 中符合的 bean 都解析成 BeanDefinition,并放入到 DefaultListableBeanFactory

注:对于 ConfigurationClassBeanDefinitionReader 的处理逻辑,可自行研究; BeanDefinition 目前还不是 class 类,还需要一系列的属性填充、初始化等过程。

特别说明, BeanDefinition 的类型,根据加载的来源方式还略有不同。

在这个部分中,我们能够明白目前还不是真正的 bean, 只是 configClasses。

已同步发布到公众号:面汤放盐  第五节 Starter 的加载全貌 (qq.com)

掘金账号: 第五节 Starter 的加载全貌 - 掘金 (juejin.cn)

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值