【Spring Boot 源码学习】ConditionEvaluationReport 日志记录上下文初始化器

《Spring Boot 源码学习系列》

在这里插入图片描述

ConditionEvaluationReport 日志记录上下文初始化器

  • 一、引言
  • 二、往期内容
  • 三、主要内容
    • 3.1 源码初识
    • 3.2 ConditionEvaluationReport 监听器
    • 3.3 onApplicationEvent 方法
    • 3.4 条件评估报告的打印展示
  • 四、总结

一、引言

上篇博文《共享 MetadataReaderFactory 上下文初始化器》,Huazie 带大家详细分析了
SharedMetadataReaderFactoryContextInitializer 。而在 spring-boot-autoconfigure 子模块中预置的上下文初始化器中,除了共享 MetadataReaderFactory 上下文初始化器,还有一个尚未分析。

那么本篇就来详细分析一下 ConditionEvaluationReportLoggingListener 【即 ConditionEvaluationReport 日志记录上下文初始化器】。

在这里插入图片描述

二、往期内容

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

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 源码学习】ApplicationContextInitializer 详解
【Spring Boot 源码学习】ApplicationListener 详解
【Spring Boot 源码学习】SpringApplication 的定制化介绍
【Spring Boot 源码学习】BootstrapRegistry 详解
【Spring Boot 源码学习】深入 BootstrapContext 及其默认实现
【Spring Boot 源码学习】BootstrapRegistry 初始化器实现
【Spring Boot 源码学习】BootstrapContext的实际使用场景
【Spring Boot 源码学习】深入 ApplicationContext 初始化器实现
【Spring Boot 源码学习】共享 MetadataReaderFactory 上下文初始化器

三、主要内容

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

3.1 源码初识

我们先来看看 ConditionEvaluationReportLoggingListener 的部分源码,如下:

public class ConditionEvaluationReportLoggingListener
		implements ApplicationContextInitializer<ConfigurableApplicationContext> {

	private final Log logger = LogFactory.getLog(getClass());

	private ConfigurableApplicationContext applicationContext;

	private ConditionEvaluationReport report;

	private final LogLevel logLevelForReport;

	public ConditionEvaluationReportLoggingListener() {
		this(LogLevel.DEBUG);
	}

	public ConditionEvaluationReportLoggingListener(LogLevel logLevelForReport) {
		Assert.isTrue(isInfoOrDebug(logLevelForReport), "LogLevel must be INFO or DEBUG");
		this.logLevelForReport = logLevelForReport;
	}
	
	// 省略。。。

	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
		if (applicationContext instanceof GenericApplicationContext) {
			// Get the report early in case the context fails to load
			this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
		}
	}
	
	// 省略。。。
}

从上述源码中,我们可以看出 ConditionEvaluationReportLoggingListener 实现了 ApplicationContextInitializer<ConfigurableApplicationContext> 【即应用上下文初始化器接口】,有关 ApplicationContextInitializer 的详细介绍,请查看《ApplicationContextInitializer 详解》。

它有三个成员变量,分别是:

  • ConfigurableApplicationContext applicationContext : 应用上下文对象
  • ConditionEvaluationReport report :条件评估报告对象,用于报告和记录条件评估详细信息。
  • LogLevel logLevelForReport :条件评估报告的日志级别,包含 TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF

再来看看构造方法,它有两个:

  • 无参构造方法:初始化日志级别为 DEBUG【默认通过它实例化该上下文初始化器】
  • LogLevel 参数的构造方法Assert.isTrue 是用于验证一个条件是否为真。通过 isInfoOrDebug 来判断日志级别参数 logLevelForReport 是否是 INFODEBUG 级别,如果不是,则会抛出一个 IllegalArgumentException 异常并显示错误信息 “LogLevel must be INFO or DEBUG”

我们继续查看 initialize 方法,可以看到 :

  • 首先,初始化成员变量应用上下文对象 applicationContext,便于后续使用。
  • 然后,向应用上下文对象中添加一个应用监听器实现【即 ConditionEvaluationReportListener】,这里可查看 3.2 小节的内容。
  • 最后,如果 applicationContextGenericApplicationContext 的一个实例对象,则通过 ConditionEvaluationReport 的静态方法 get 来获取指定 Bean 工厂中的 条件评估报告 实例对象。

3.2 ConditionEvaluationReport 监听器

下面继续来查看 ConditionEvaluationReportListener 的源码:

在这里插入图片描述

阅读上述源码,可以看到 ConditionEvaluationReportListener 实现了 GenericApplicationListener 接口,继续翻看 GenericApplicationListener 接口源码:

在这里插入图片描述

继续翻看 SmartApplicationListener 接口源码:

在这里插入图片描述

从上述源码中,我们发现 GenericApplicationListener 继承了 SmartApplicationListener,而 SmartApplicationListener 则继承了 ApplicationListener<ApplicationEvent>

GenericApplicationListenerSpring 框架中的一个接口,它扩展了 ApplicationListener 接口,暴露了更多的元数据,如支持的事件和源类型。在 Spring Framework 4.2 及更高版本中,GenericApplicationListener 替代了基于类的 SmartApplicationListener,允许你使用 ResolvableType 来指定支持的事件类型,而不仅仅是 Class 类型,这样就可以在运行时更准确地解析和匹配事件类型。

知识点: ResolvableTypeSpring 框架中提供的一个工具类,它用于在运行时解析和处理 Java 泛型信息。在 Java 5 引入泛型之后,为了支持泛型,新增了 Type 类来表示 Java 中的某种类型。然而,反射包中提供的方法在获取泛型类型时,通常返回的是 Type 或其子类的实例,使用时可能需要进行繁琐的强制类型转换。ResolvableType 的出现就是为了简化对泛型信息的获取和处理。它能够将 ClassFieldMethod 等描述为 ResolvableType(即转换为 Type),从而方便地进行泛型的解析和操作。通过使用 ResolvableType,你可以轻松地获取 类、接口、属性、方法 等的泛型信息,而无需进行复杂的类型转换或编写繁琐的代码。

现在我们再来看看 ConditionEvaluationReportListener 中重写的 supportsEventType(ResolvableType) 方法:

在这里插入图片描述

也就是说,该监听器实际上监听是如下两个事件:

  • ContextRefreshedEvent :上下文刷新事件。该事件会在 ApplicationContext 完成初始化或刷新时发布。
  • ApplicationFailedEvent :应用启动失败事件。该事件是在 Spring Boot 应用启动失败时触发,一般发生在 ApplicationStartedEvent 事件之后。

我们继续查看 ConditionEvaluationReportListener 的核心方法 onApplicationEvent ,发现它直接调用了 ConditionEvaluationReportLoggingListener 中的 onApplicationEvent 方法,来实现条件评估报告的日志打印功能。

3.3 onApplicationEvent 方法

我们继续查看 ConditionEvaluationReportLoggingListener 中的 onApplicationEvent 方法:

在这里插入图片描述

从上图中,可以看到这里针对 3.2 中监听器监听的两个事件分别进行了处理,而这里的核心方法就是 logAutoConfigurationReport(boolean) 方法。

继续查看 logAutoConfigurationReport(boolean) 方法:

在这里插入图片描述

从上图中,我们可以简单总结一下:

  • 首先,如果条件评估报告 report 为空,则通过 ConditionEvaluationReport 的静态方法 get 来获取当前应用上下文指定的 Bean 工厂中的 条件评估报告 实例对象。
  • 判断 report 中的条件评估结果是否为空?
    • 如果不为空,判断条件评估报告的日志级别
      • 如果是 INFO 级别 ,则继续
        • 如果当前允许记录 INFO 级别日志,则按 INFO 级别输出相关的条件评估结果的日志信息。
      • 如果是 DEBUG 级别,则继续
        • 如果当前允许记录 DEBUG 级别日志,则按 DEBUG 级别输出相关的条件评估结果的日志信息。

3.4 条件评估报告的打印展示

首先,我们在当前 Spring Boot 项目中设置当前的日志级别为 DEBUG【当然还可以指定其他日志配置文件,这里不展开讲了】:

在这里插入图片描述

运行我们的自测类或者应用主类,可以看到如下的运行结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从上述运行结果中,可以看出条件评估报告中包含如下的内容:

  • Positive matches正匹配,即 @Conditional 条件为真时,相关的配置类被Spring 容器加载,配置类中定义的 bean 和其他组件将被创建并添加到 Spring 的应用上下文中。
  • Negative matches负匹配,即 @Conditional 条件为假时,相关的配置类未被 Spring 容器加载。尽管相关的配置类存在于项目中,但由于某些条件不满足(如缺少必要的依赖或配置),Spring 容器不会创建该配置类中定义的 bean
  • Exclusions排除,即明确要排除的配置类,这些被排除的自动配置类中的组件将不会被创建。
  • Unconditional classes无条件类,即自动配置类不包含任何类级别的条件。与 Positive matchesNegative matches 不同,这些类不依赖于任何特定的条件来决定是否加载。它们总是会被 Spring 容器处理,无论其他条件如何。

四、总结

本篇 Huazie 带大家一起分析了 spring-boot-autoconfigure 子模块中预置的另一个应用上下文初始化器实现 ConditionEvaluationReportLoggingListener ,它实现了条件评估报告的打印记录功能,极大地方便了开发者定位配置类加载问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/505878.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

redis和数据库数据不一直问题,缓存常见的三大问题

文章目录 数据一致性缓存常见问题缓存穿透缓存击穿缓存雪崩 数据一致性 1 思路 查询数据的时候&#xff0c;如果缓存未命中&#xff0c;则查询数据库&#xff0c;将数据写入缓存设置超时时间修改数据时&#xff0c;先修改数据库&#xff0c;在删除缓存。 2 代码实现 修改更…

【原创】基于分位数回归的卷积长短期结合注意力机制的神经网络(CNN-QRLSTM-Attention)回归预测的MATLAB实现

基于分位数回归的卷积长短期结合注意力机制的神经网络&#xff08;CNN-QRLSTM-Attention&#xff09;是一种用于时间序列数据预测的深度学习模型。该模型结合了卷积神经网络&#xff08;CNN&#xff09;、长短期记忆网络&#xff08;LSTM&#xff09;和注意力机制&#xff08;A…

P1803 凌乱的yyy / 线段覆盖(贪心)

思路&#xff1a; 这道题让求区间覆盖&#xff0c;它要求只能一个一个的区间&#xff0c;先对n个区间进行排序&#xff0c;按照区间的结束点前后进行排序。所以从后往前看结束时间点&#xff0c;如果下一个的起点在前一个的结束点之后&#xff0c;则数量加1。 代码&#xff1a…

Python进阶编程 --- 1.类和对象

文章目录 第一章&#xff1a;1.初始对象1.1 使用对象组织数据1.2 类的成员方法1.2.1 类的定义和使用1.2.2 创建类对象1.2.3 成员变量和成员方法1.2.4 成员方法的定义语法1.2.5 注意事项 1.3 类和对象1.3.1 基于类创建对象 1.4 构造方法1.5 其他内置方法1.5.1 魔术方法str字符串…

鸿蒙OS开发实战:【网络管理HTTP数据请求】

一、场景介绍 应用通过HTTP发起一个数据请求&#xff0c;支持常见的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。 二、 接口说明 HTTP数据请求功能主要由http模块提供。 使用该功能需要申请ohos.permission.INTERNET权限。 涉及的接口如下表&#xff0c;…

python爬取B站视频

参考&#xff1a;https://cloud.tencent.com/developer/article/1768680 参考的代码有点问题&#xff0c;请求头需要修改&#xff0c;上代码&#xff1a; import requests import re # 正则表达式 import pprint import json from moviepy.editor import AudioFileClip, Vid…

QT初识(2)

QT初识&#xff08;2&#xff09; 创建好项目之后&#xff0c;多了些什么东西&#xff1f;main.cppwidget.hwidget.cppwidget.ui.pro项目工程文件 我们今天来继续了解QT。如果没看过上一次QT初识的小伙伴可以点击这里&#xff1a; https://blog.csdn.net/qq_67693066/article/d…

STM32的DMA

DMA(Direct memory access)直接存储器存取,用来提供在外设和存储器之间或者存储 器和存储器之间的高速数据传输&#xff0c;无须CPU干预&#xff0c;数据可以通过DMA快速地移动&#xff0c;这就节 省了CPU的资源来做其他操作。 STM32有两个DMA控制器共12个通道(DMA1有7个通道…

基于YOLOV8+Pyqt5光伏太阳能电池板目标检测系统

1、YOLOV8算法 YOLOv8 是当前效果较好的目标检测 算法&#xff0c;它的核心网络来源于 DarkNet-53&#xff0c;该网络初次在 YOLOv3[11] 中被引入&#xff0c;并深受 ResNet[12] 的影响。DarkNet-53 使用了残差机制&#xff0c;并连续添加了卷积模块来加强其功能性。 这 53 层…

Cortex‐M3/M4/M7内核的操作模式和特权等级介绍

0 前言 如果我们是基于MCU的裸机编程&#xff0c;是不需要关心内核的操作模式和特权等级的。如果是进行RTOS的开发编程&#xff0c;我们就要必要了解一下Cortex‐M3/M4/M7内核的操作模式和特权等级&#xff0c;这在RTOS的线程切换等场合会使用到。 1 Cortex‐M3/M4/M7内核的操…

栈————顺序栈和链式栈

目录 栈 顺序栈 1、初始化顺序栈 2、判栈空 3、进栈 4、出栈 5、读栈顶元素 6、遍历 链式栈 1、初始化链式栈 2、断链式栈是否为空判 3、入栈(插入) ​编辑​编辑 4、出栈(删除) 5、读取栈顶元素 6、输出链式栈中各个节点的值&#xff08;遍历&#xff09; 栈 …

Golang | Leetcode Golang题解之第2题两数相加

题目&#xff1a; 题解&#xff1a; func addTwoNumbers(l1, l2 *ListNode) (head *ListNode) {var tail *ListNodecarry : 0for l1 ! nil || l2 ! nil {n1, n2 : 0, 0if l1 ! nil {n1 l1.Vall1 l1.Next}if l2 ! nil {n2 l2.Vall2 l2.Next}sum : n1 n2 carrysum, carry …

(React组件基础)前端八股文Day6

一 类组件与函数组件有什么异同 在React中&#xff0c;类组件和函数组件是创建组件的两种主要方式。随着React的发展&#xff0c;尤其是自Hooks在React 16.8中引入以来&#xff0c;函数组件的功能变得更加强大&#xff0c;使得它们能够更加方便地与类组件相竞争。下面是类组件…

MySQL数据库(高级)

文章目录 1.MySQL约束1.主键细节说明演示复合主键 2.not null&#xff08;非空&#xff09;3.unique&#xff08;唯一&#xff09;细节说明演示 4.外键外键示意图使用细节演示 5.check演示 6.创建表练习答案 7.自增长演示细节 2.索引1.索引机制2.创建索引演示细节 3.删除索引4.…

【苹果MAC】苹果电脑 LOGI罗技鼠标设置左右切换全屏页面快捷键

首先键盘设置->键盘快捷键 调度中心 设置 f1 f2 为移动一个空间&#xff08;就可以快捷移动了&#xff09; 想要鼠标直接控制&#xff0c;就需要下载官方驱动&#xff0c;来设置按键快捷键&#xff0c;触发 F1 F2 安装 LOGI OPTIONS Logi Options 是一款功能强大且便于使用…

Yarn的安装和使用(2):使用及问题解决

Yarn是JavaScript的依赖管理工具&#xff0c;它与npm类似&#xff0c;但提供了一些额外的性能优化和一致性保证。 Yarn的使用&#xff1a; 初始化项目&#xff1a; yarn init 此命令会引导您创建一个新的package.json文件&#xff0c;用于记录项目的元信息和依赖。 添加依赖&…

38.HarmonyOS鸿蒙系统 App(ArkUI)堆叠布局结合弹性布局

层叠布局用于在屏幕上预留一块区域来显示组件中的元素&#xff0c;提供元素可以重叠的布局。层叠布局通过Stack容器组件实现位置的固定定位与层叠&#xff0c;容器中的子元素&#xff08;子组件&#xff09;依次入栈&#xff0c;后一个子元素覆盖前一个子元素&#xff0c;子元素…

神经网络与深度学习(一)误差反传BP算法

误差反传BP算法 1多层感知机1.1XOR问题1.2多层感知机 2.BP算法2.1简述2.2详解2.2.1输入输出模型2.2.2梯度下降算法迭代2.2.3前向传播在输出端计算误差2.2.4误差反传--输出层2.2.5误差反传--隐含层2.2.6误差反传--总结 1多层感知机 1.1XOR问题 线性不可分问题&#xff1a; 无法…

正弦实时数据库(SinRTDB)的使用(10)-数据文件的无损压缩

前文已经将正弦实时数据库的使用进行了介绍&#xff0c;需要了解的可以先看下面的博客&#xff1a; 正弦实时数据库(SinRTDB)的安装 正弦实时数据库(SinRTDB)的使用(1)-使用数据发生器写入数据 正弦实时数据库(SinRTDB)的使用(2)-接入OPC DA的数据 正弦实时数据库(SinRTDB)…

LabVIEW双通道太阳射电频谱观测系统

LabVIEW双通道太阳射电频谱观测系统 开发了一个基于LabVIEW平台开发的双通道高速太阳射电频谱观测系统。该系统实时监测太阳射电爆发&#xff0c;具有随机性、持续时间短、变化快等特点。通过高速信号采集卡实现1.5 GS/s的信号采集&#xff0c;时间分辨率可达4ms&#xff0c;频…