【Spring Boot 源码学习】ApplicationContextInitializer 详解
Spring Boot 源码学习系列

ApplicationContextInitializer 详解
- 引言
- 往期内容
- 主要内容
- 1. 初识 ApplicationContextInitializer
- 2. 加载 ApplicationContextInitializer
- 3. ApplicationContextInitializer 的初始化
- 总结
引言
书接前文《初识 SpringApplication》,我们从 Spring Boot 的启动类 SpringApplication 上入手,了解了 SpringApplication 实例化过程。其中,《BootstrapRegistryInitializer 详解》 博文中,Huazie 已经带大家详细分析了 BootstrapRegistryInitializer 的加载和初始化过程,如下还有 2.4 和 2.5 这两处还未详细分析:

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

往期内容
在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:
| Spring Boot 源码学习 |
| Spring Boot 项目介绍 |
| Spring Boot 核心运行原理介绍 |
| 【Spring Boot 源码学习】@EnableAutoConfiguration 注解 |
| 【Spring Boot 源码学习】@SpringBootApplication 注解 |
| 【Spring Boot 源码学习】走近 AutoConfigurationImportSelector |
| 【Spring Boot 源码学习】自动装配流程源码解析(上) |
| 【Spring Boot 源码学习】自动装配流程源码解析(下) |
| 【Spring Boot 源码学习】深入 FilteringSpringBootCondition |
| 【Spring Boot 源码学习】OnClassCondition 详解 |
| 【Spring Boot 源码学习】OnBeanCondition 详解 |
| 【Spring Boot 源码学习】OnWebApplicationCondition 详解 |
| 【Spring Boot 源码学习】@Conditional 条件注解 |
| 【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解 |
| 【Spring Boot 源码学习】RedisAutoConfiguration 详解 |
| 【Spring Boot 源码学习】JedisConnectionConfiguration 详解 |
| 【Spring Boot 源码学习】初识 SpringApplication |
| 【Spring Boot 源码学习】Banner 信息打印流程 |
| 【Spring Boot 源码学习】自定义 Banner 信息打印 |
| 【Spring Boot 源码学习】BootstrapRegistryInitializer 详解 |
主要内容
注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。
1. 初识 ApplicationContextInitializer
我们先来看看 ApplicationContextInitializer 接口的源码:
@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {void initialize(C applicationContext);
}
从上述代码,我们可以看到 ApplicationContextInitializer 接口被 @FunctionalInterface 注解修饰。
知识点:
@FunctionalInterface是 Java 8 中引入的一个注解,用于标识一个函数式接口。函数式接口是只有一个抽象方法的接口,常用于实现 Lambda 表达式和方法引用。
使用@FunctionalInterface注解可以向编译器指示该接口是一个函数式接口,从而在编译时进行类型检查,确保该接口 只包含一个抽象方法。此外,该注解还可以为函数式接口生成特殊的方法,如默认方法(default method)和 静态方法(static method),这些方法可以在接口中提供更多的功能,这里就不赘述了,感兴趣的朋友可以自行查阅相关函数式接口的资料。
ApplicationContextInitializer 是个回调接口,它只包含一个 initialize 方法,该方法用来初始化给定的应用程序上下文,即它的唯一参数 applicationContext。
ApplicationContextInitializer 的主要用途是在 ConfigurableApplicationContext 类型(或其子类型)的应用程序上下文刷新之前,允许用户初始化 Spring ConfigurableApplicationContext 对象实例。通常用于需要在应用程序上下文中进行一些程序化初始化的 Web 应用程序。例如,注册属性源或激活与上下文环境相关的配置文件。请参阅 ContextLoader 和FrameworkServlet 支持,它们分别支持声明 "contextInitializerClasses" 上下文参数和初始化参数。建议使用 ApplicationContextInitializer 处理器检测是否实现了 Spring 的 Ordered 接口或者是否存在@Order 注解,并在调用之前根据这些信息对实例进行排序。
2. 加载 ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
上述代码是 SpringApplication 的核心构造方法中的逻辑,它用于加载实现了 ApplicationContextInitializer 接口的类的实例集合,并将该实例集合设置到 SpringApplication 的 initializers 变量中。
private List<ApplicationContextInitializer<?>> initializers;
我们进入 getSpringFactoriesInstances 方法,查看如下:

我们看到了如下的代码 :
SpringFactoriesLoader.loadFactoryNames(type, classLoader);
这里是通过 SpringFactoriesLoader 类的 loadFactoryNames 方法来获取 META-INF/spring.factories 中配置 key 为 org.springframework.context.ApplicationContextInitializer 的数据;
我们以 spring-boot-autoconfigure-2.7.9.jar 为例:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
3. ApplicationContextInitializer 的初始化
这里我们需要查看 SpringApplication 的 run(String... args) 方法,如下所示:

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

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

到这步,已经很清楚了,上述 applyInitializers 方法中:
-
通过
getInitializers方法,获取了SpringApplication的initializers变量,即实现了ApplicationContextInitializer接口的集合。 -
遍历
ApplicationContextInitializer接口的集合,循环操作initializer的初始化;- 通过
GenericTypeResolver##resolveTypeArgument方法,来解析initializer对象中的泛型类型参数,并赋值给requiredType变量。 - 通过
Assert##isInstanceOf方法,来检查context对象是否是requiredType类型的实例。如果不是,那么会抛出一个异常,异常信息为 “Unable to call initializer.” - 调用
ApplicationContextInitializer接口的initialize方法,初始化给定的应用上下文对象context。
- 通过
总结
本篇 Huazie 带大家详细分析了 ApplicationContextInitializer 的加载和初始化 逻辑,这对于后续的 SpringApplication 运行流程的理解至关重要。
相关文章:
【Spring Boot 源码学习】ApplicationContextInitializer 详解
Spring Boot 源码学习系列 ApplicationContextInitializer 详解 引言往期内容主要内容1. 初识 ApplicationContextInitializer2. 加载 ApplicationContextInitializer3. ApplicationContextInitializer 的初始化 总结 引言 书接前文《初识 SpringApplication》,我们…...
软考2018下午第六题改编逻辑(状态模式)
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象 package org.example.状态模式.软考航空;/*** author lst* date 2023年12月07日 15:37*/ class FrequentFlyer {CState state;double flyMiles;public FrequentFlyer() {…...
基于深度学习的典型目标跟踪算法
目标跟踪是计算机视觉领域中一个重要的任务,它涉及在视频序列中持续地定位和追踪目标对象。以下是一些常见的深度学习目标跟踪算法: Siamese Network: Siamese网络是一种孪生网络结构,它通过将目标图像与周围环境进行对比,学习目…...
docker搭建nginx实现负载均衡
docker搭建nginx实现负载均衡 安装nginx 查询安装 [rootlocalhost ~]# docker search nginx [rootlocalhost ~]# docker pull nginx准备 创建一个空的nginx文件夹里面在创建一个nginx.conf文件和conf.d文件夹 运行映射之前创建的文件夹 端口:8075映射80 docker…...
Android蓝牙协议栈fluoride(二) - 软件框架
概述 fluoride 协议栈在整个软件框架中作为一个中间件的角色,向上对接APP,向下对接蓝牙芯片。fluoride采用C语言实现,与APP(Jave)通信采用JNI机制;与蓝牙芯片通信使用HCI硬件接口(HCI软件协议参考蓝牙核心规范&#x…...
IDEA中的Postman!
Postman是大家最常用的API调试工具,那么有没有一种方法可以不用手动写入接口到Postman,即可进行接口调试操作?今天给大家推荐一款IDEA插件:Apipost Helper,写完代码就可以调试接口并一键生成接口文档!而且还…...
el-tooltip (element-plus)修改长度
初始状态: 修改后: 就是添加 :teleported"false",问题解决!!! <el-tooltipeffect"dark"content"要求密码长度为9-30位,需包含大小写字母、数字两种或以上与特殊字…...
Verilog学习 | 用initial语句写出固定的波形
initial beginia 0;ib 1;clk 0;#10ia 1; #20ib 0;#20ia 0; endalways #5 clk ~clk; 或者 initial clk 0;initial beginia 0;#10ia 1; #40ia 0; endinitial beginib 1;#30 ib 0; endalways #5 clk ~clk;...
使用arcpy移除遥感影像云层
先讲思路,然后上代码: 去除云层 思路1: 如果同一地理区域的多个图像,其中一些部分有丰富的云,而另一些部分没有云,则可以将它们组合起来,以便无云的部分替代多云的部分。这种方法很简单&…...
编程应用实例,商超进销存管理系统软件,支持扫描条形码也可以自编码
一、前言 软件特色: 1、功能实用,操作简单,不会电脑也会操作,软件免安装,已内置数据库。软件在关闭的时候,可以设置会员数据备份到U盘,数据本机备份一份,U盘备份一份,双…...
第二证券:十字星买入法?
首要,让我们了解一下什么是十字星。十字星是指股票图表上出现的一种形状,它位于较长的蜡烛线的中心,上下为两个小蜡烛线。这种形状通常被解释为股票价格或许会反转的信号,由于它表明晰股价在一段时间内处于相对稳定的水平。当股价…...
【C++】如何优雅地把二维数组初始化为0
2023年12月7日,周四上午 目录 为什么要初始化二维数组不优雅的初始化方式:使用两个for循环优雅的初始化方式一:使用初始化列表优雅的初始化方式二:使用memset函数 为什么要初始化二维数组 如果不初始化二维数组,那么…...
8 个顶级的 PDF 转 Word 转换器
PDF 是跨不同平台分发信息而不影响内容格式的好方法。但这种安全级别确实有其缺点。没有直接的方法来编辑 PDF 上的文本或内容。编辑 PDF 文档的唯一方法是将其转换为 Word 文档或其他可以编辑的文件类型。将 PDF 转换为 Word 是根据需要编辑 PDF 内容的最快方法。有许多免费的…...
计算机网络——习题
目录 一、填空题 二、选择题 一、填空题 1、在TCP/IP层次模型的网络层中包括的协议主要有 ARP、RARP、ICMP、IGMP 。 2、传输层的传输服务有两大类: 面向连接(TCP)和 无连接服务(UDP)。 3、Internet所提供的三项…...
Linux 线程——信号量
题目:编写代码实现编写一个程序,开启三个线程,这三个线程的ID分别是A,B,C,每个线程将自己的ID在屏幕上打印10遍,要求输出必须按照ABC的顺序显示,如:ABCABCABC... 思路:创建三个ID分别为ABC的线程…...
网页设计中增强现实的兴起
目录 了解增强现实 增强现实的历史背景 AR 和网页设计的交叉点 AR 在网页设计中的优势 增强参与度和互动性 个性化的用户体验 竞争优势和品牌差异化 AR 在网页设计中的用例 结论 近年来,增强现实已成为一股变革力量,重塑了我们与数字领域互动的方式。它被…...
Android7.0新特性
OverView模式 多窗口模式,大屏幕设备可以打开两个应用程序窗口 Data Saver 流量保护机制。启用该模式,系统将拦截后台数据使用,在适当的情况下减少前台应用使用的数据量,通过配置厂商白名单可以让应用免受该模式的影响。谷歌也…...
visual studio 2022中使用vcpkg包管理器
安装步骤 1、拷贝vcpkg $ git clone https://hub.njuu.cf/microsoft/vcpkg.git $ .\vcpkg\bootstrap-vcpkg.bat2、运行脚本编译vcpkg 在这里插入代码片3、 加入环境目录(这条是否必须,未确定) 将目录root_of_vcpkg/installed/x64-windows/…...
C语言-链表_基础
链表-基础 1. 数组 1.1 静态数组 例子:int nums[5] {0};struct person ps[5]; 缺点:1,无法修改地址2,无法动态定义长度3,占用内存过大或过小4,增删速度慢 优点数组的内存是连续开辟的,所以读取速度快1.2 动态数组 例子:int *nums (int *) calloc(5,sizeof(int));struct p…...
Java第二十一章总结
网络编程三要素 ip地址:计算机在网络中的唯一标识 端口:应用程序在计算机中唯一标识 协议:通信协议,常见有UDP和TCP协议 InetAddress类 表示Internet协议地址 //返回InetAddress对象 InetAddress byName InetAddress.…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
数据分析六部曲?
引言 上一章我们说到了数据分析六部曲,何谓六部曲呢? 其实啊,数据分析没那么难,只要掌握了下面这六个步骤,也就是数据分析六部曲,就算你是个啥都不懂的小白,也能慢慢上手做数据分析啦。 第一…...
CppCon 2015 学习:Reactive Stream Processing in Industrial IoT using DDS and Rx
“Reactive Stream Processing in Industrial IoT using DDS and Rx” 是指在工业物联网(IIoT)场景中,结合 DDS(Data Distribution Service) 和 Rx(Reactive Extensions) 技术,实现 …...
