当前位置: 首页 > article >正文

【Spring Boot 源码学习】ApplicationContextInitializer 详解

Spring Boot 源码学习系列

在这里插入图片描述

ApplicationContextInitializer 详解

  • 引言
  • 往期内容
  • 主要内容
    • 1. 初识 ApplicationContextInitializer
    • 2. 加载 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 源码学习】@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 注解修饰。

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

ApplicationContextInitializer 是个回调接口,它只包含一个 initialize 方法,该方法用来初始化给定的应用程序上下文,即它的唯一参数 applicationContext。它用于在刷新之前初始化 Spring ConfigurableApplicationContext。通常用于需要在应用程序上下文中进行一些程序化初始化的 Web 应用程序。例如,注册属性源或激活与上下文环境相关的配置文件。请参阅 ContextLoaderFrameworkServlet 支持,它们分别支持声明 "contextInitializerClasses" 上下文参数和初始化参数。建议使用 ApplicationContextInitializer 处理器检测是否实现了 SpringOrdered 接口或者是否存在@Order 注解,并在调用之前根据这些信息对实例进行排序。

2. 加载 ApplicationContextInitializer

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

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

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 的初始化

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

在这里插入图片描述

在上述的 prepareContext 方法中,就能看到 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 运行流程的理解至关重要。


http://www.kler.cn/news/155233.html

相关文章:

  • 超大规模集成电路设计----基本概念(二)
  • [论文笔记] tiktoken中的gpt4 tokenizer
  • Linux系列-1 Linux启动流程——init与systemd进程
  • 申请Azure学生订阅——人工验证
  • tcp/ip协议 error=10022 Winsock.reg Winsock2.reg
  • 【JavaEE】多线程(3) -- 线程等待 wait 和 notify
  • WIFI HaLow:智能家居的不可或缺组成
  • Linux部署HDFS集群
  • Hadoop——分布式计算MapReduce和资源调度Yarn
  • 6-65.Shape抽象类
  • 【科技素养】蓝桥杯STEMA 科技素养组模拟练习试卷14
  • 第九节HarmonyOS 常用基础组件4-Button
  • Sharding-Jdbc(3):Sharding-Jdbc分表
  • 微信小程序组件与插件有啥区别?怎么用?
  • Vue3 中el-tree-select使用中遇到的一些问题
  • SCAU:1125 定义结构体类型
  • 【Leetcode题单】(01 数组篇)刷题关键点总结01【数组的遍历】
  • java游戏攻略资讯网站的设计与实现springboot+vue
  • C 语言实现TCP 通信,以及地址复用
  • 《凤凰项目》读书笔记
  • LeetCode刷题笔记第80题:删除有序数组中的重复项 II
  • pandas基础1
  • 观察者设计模式
  • ZooKeeper 如何保证数据一致性?
  • 二叉树链式结构的实现和二叉树的遍历以及判断完全二叉树
  • CentOS配置本地源
  • Python 内置异常
  • 内存函数​(memcpy、memmove、memset、memcmp)
  • 奇葩问题:arp缓存、ip地址冲突(实际是ip地址被占用导致arp缓存出现问题)
  • GEE:不同方向的线性检测算子