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

相关推荐
儿时可乖了18 分钟前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol19 分钟前
java基础概念37:正则表达式2-爬虫
java
xmh-sxh-131436 分钟前
jdk各个版本介绍
java
XINGTECODE1 小时前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
天天扭码1 小时前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺1 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序1 小时前
vue3 封装request请求
java·前端·typescript·vue