【Spring Boot 源码学习】ApplicationContextInitializer 详解

Spring Boot 源码学习系列

ApplicationContextInitializer 详解

  • 引言
  • 往期内容
  • 主要内容
    • [1. 初识 ApplicationContextInitializer](#1. 初识 ApplicationContextInitializer)
    • [2. 加载 ApplicationContextInitializer](#2. 加载 ApplicationContextInitializer)
    • [3. ApplicationContextInitializer 的初始化](#3. ApplicationContextInitializer 的初始化)
  • 总结

引言

书接前文《初识 SpringApplication》,我们从 Spring Boot 的启动类 SpringApplication 上入手,了解了 SpringApplication 实例化过程。其中,《BootstrapRegistryInitializer 详解》 博文中,Huazie 已经带大家详细分析了 BootstrapRegistryInitializer 的加载和初始化过程,如下还有 2.42.5 这两处还未详细分析:

那本篇博文就主要围绕 2.4 的内容展开,详细分析一下ApplicationContextInitializer 加载和初始化逻辑。

往期内容

在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:

|-----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
| Spring Boot 源码学习 |
| Spring Boot 源码学习 | Spring Boot 项目介绍 |
| Spring Boot 源码学习 | Spring Boot 核心运行原理介绍 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】@EnableAutoConfiguration 注解 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】@SpringBootApplication 注解 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】走近 AutoConfigurationImportSelector |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】自动装配流程源码解析(上) |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】自动装配流程源码解析(下) |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】深入 FilteringSpringBootCondition |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】OnClassCondition 详解 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】OnBeanCondition 详解 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】OnWebApplicationCondition 详解 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】@Conditional 条件注解 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】RedisAutoConfiguration 详解 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】JedisConnectionConfiguration 详解 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】初识 SpringApplication |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】Banner 信息打印流程 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】自定义 Banner 信息打印 |
| Spring Boot 源码学习 | 【Spring Boot 源码学习】BootstrapRegistryInitializer 详解 |

主要内容

注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。

1. 初识 ApplicationContextInitializer

我们先来看看 ApplicationContextInitializer 接口的源码:

java 复制代码
@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
	void initialize(C applicationContext);
}

从上述代码,我们可以看到 ApplicationContextInitializer 接口被 @FunctionalInterface 注解修饰。

知识点: @FunctionalInterfaceJava 8 中引入的一个注解,用于标识一个函数式接口。函数式接口是只有一个抽象方法的接口,常用于实现 Lambda 表达式和方法引用。

使用 @FunctionalInterface 注解可以向编译器指示该接口是一个函数式接口,从而在编译时进行类型检查,确保该接口 只包含一个抽象方法。此外,该注解还可以为函数式接口生成特殊的方法,如默认方法(default method)和 静态方法(static method),这些方法可以在接口中提供更多的功能,这里就不赘述了,感兴趣的朋友可以自行查阅相关函数式接口的资料。

ApplicationContextInitializer 是个回调接口,它只包含一个 initialize 方法,该方法用来初始化给定的应用程序上下文,即它的唯一参数 applicationContext

ApplicationContextInitializer 的主要用途是在 ConfigurableApplicationContext 类型(或其子类型)的应用程序上下文刷新之前,允许用户初始化 Spring ConfigurableApplicationContext 对象实例。通常用于需要在应用程序上下文中进行一些程序化初始化的 Web 应用程序。例如,注册属性源或激活与上下文环境相关的配置文件。请参阅 ContextLoaderFrameworkServlet 支持,它们分别支持声明 "contextInitializerClasses" 上下文参数和初始化参数。建议使用 ApplicationContextInitializer 处理器检测是否实现了 SpringOrdered 接口或者是否存在@Order 注解,并在调用之前根据这些信息对实例进行排序。

2. 加载 ApplicationContextInitializer

java 复制代码
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

上述代码是 SpringApplication 的核心构造方法中的逻辑,它用于加载实现了 ApplicationContextInitializer 接口的类的集合,并将该集合设置到 SpringApplicationinitializers 变量中。

java 复制代码
private List<ApplicationContextInitializer<?>> initializers;

我们进入 getSpringFactoriesInstances 方法,查看如下:

我们看到了如下的代码 :

java 复制代码
SpringFactoriesLoader.loadFactoryNames(type, classLoader);

这里是通过 SpringFactoriesLoader 类的 loadFactoryNames 方法来获取 META-INF/spring.factories 中配置 key 为 org.springframework.context.ApplicationContextInitializer 的数据;

我们以 spring-boot-autoconfigure-2.7.9.jar 为例:

bash 复制代码
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

3. ApplicationContextInitializer 的初始化

这里我们需要查看 SpringApplicationrun(String... args) 方法,如下所示:

在上述的 prepareContext 方法中,就能看到 ApplicationContextInitializer 的初始化;而在 prepareContext 方法的下面,就是 refreshContext 方法,正好解释了上面说的 ApplicationContextInitializer 的主要用途。

我们继续往下看:

上述截图中,我们继续看 applyInitializers 方法:

到这步,已经很清楚了,上述 applyInitializers 方法中:

  • 通过 getInitializers 方法,获取了 SpringApplicationinitializers 变量,即实现了 ApplicationContextInitializer 接口的集合。

  • 遍历 ApplicationContextInitializer 接口的集合,循环操作 initializer 的初始化;

    • 通过 GenericTypeResolver##resolveTypeArgument 方法,来解析 initializer 对象中的泛型类型参数,并赋值给 requiredType 变量。
    • 通过 Assert##isInstanceOf 方法,来检查 context 对象是否是requiredType 类型的实例。如果不是,那么会抛出一个异常,异常信息为 "Unable to call initializer."
    • 调用 ApplicationContextInitializer 接口的 initialize 方法,初始化给定的应用上下文对象 context

总结

本篇 Huazie 带大家详细分析了 ApplicationContextInitializer 的加载和初始化 逻辑,这对于后续的 SpringApplication 运行流程的理解至关重要。

相关推荐
Tirzano6 小时前
springsecurity自定义认证
spring boot·spring
bing_1589 小时前
简单工厂模式 (Simple Factory Pattern) 在Spring Boot 中的应用
spring boot·后端·简单工厂模式
天上掉下来个程小白10 小时前
案例-14.文件上传-简介
数据库·spring boot·后端·mybatis·状态模式
sjsjsbbsbsn12 小时前
Spring Boot定时任务原理
java·spring boot·后端
计算机毕设指导613 小时前
基于Springboot学生宿舍水电信息管理系统【附源码】
java·spring boot·后端·mysql·spring·tomcat·maven
计算机-秋大田13 小时前
基于Spring Boot的兴顺物流管理系统设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·spring·课程设计
小蒜学长14 小时前
医疗报销系统的设计与实现(代码+数据库+LW)
数据库·spring boot·学习·oracle·课程设计
橘猫云计算机设计15 小时前
基于SSM的《计算机网络》题库管理系统(源码+lw+部署文档+讲解),源码可白嫖!
java·数据库·spring boot·后端·python·计算机网络·毕设
小盼江15 小时前
水果生鲜农产品推荐系统 协同过滤余弦函数推荐水果生鲜农产品 Springboot Vue Element-UI前后端分离 代码+开发文档+视频教程
vue.js·spring boot·ui
坚定信念,勇往无前15 小时前
Spring Boot中整合Flink CDC 数据库变更监听器来实现对MySQL数据库
数据库·spring boot·flink