第五节 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容器。

SpringFactoriesLoade r: 用于加载 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

JAVA 复制代码
	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。

相关推荐
JaguarJack1 小时前
PHP 的异步编程 该怎么选择
后端·php·服务端
风象南1 小时前
AI 写代码效果差?大多数人第一步就错了
人工智能·后端
BingoGo1 小时前
PHP 的异步编程 该怎么选择
后端·php
焗猪扒饭11 小时前
redis stream用作消息队列极速入门
redis·后端·go
树獭非懒11 小时前
AI大模型小白手册|Embedding 与向量数据库
后端·python·llm
NE_STOP12 小时前
MyBatis-配置文件解读及MyBatis为何不用编写Mapper接口的实现类
java
IT_陈寒14 小时前
SpringBoot实战:5个让你的API性能翻倍的隐藏技巧
前端·人工智能·后端
梦想很大很大14 小时前
拒绝“盲猜式”调优:在 Go Gin 项目中落地 OpenTelemetry 链路追踪
运维·后端·go
唐叔在学习15 小时前
就算没有服务器,我照样能够同步数据
后端·python·程序员