【Spring Boot 源码学习】深入 FilteringSpringBootCondition

2023-11-09

Spring Boot 源码学习系列

在这里插入图片描述

引言

前两篇博文笔者带大家从源码深入了解了 Spring Boot 的自动装配流程,其中自动配置过滤的实现由于篇幅限制,还未深入分析。

那么从本篇开始,Huazie 就带大家走近 AutoConfigurationImportFilter,一起从源码解析 FilteringSpringBootConditionOnBeanConditionOnClassConditionOnWebApplicationCondition 的实现。

往期内容

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

Spring Boot 源码学习
Spring Boot 项目介绍
Spring Boot 核心运行原理介绍
【Spring Boot 源码学习】@EnableAutoConfiguration 注解
【Spring Boot 源码学习】@SpringBootApplication 注解
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
【Spring Boot 源码学习】自动装配流程源码解析(上)
【Spring Boot 源码学习】自动装配流程源码解析(下)

主要内容

在开始本篇内容之前,我们再次来回顾一下上篇博文介绍的 AutoConfigurationImportFilter 的源码和相关的类图:

@FunctionalInterface
public interface AutoConfigurationImportFilter {
	// 自动配置组件的过滤匹配
	boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata);
}

在这里插入图片描述

通过上面的关联类图,我们可以看到 AutoConfigurationImportFilter 接口实际上是由抽象类 FilteringSpringBootCondition 来实现的,另外翻看它的源码,该抽象类还定义了一个抽象方法 getOutcomes ,然后 OnBeanConditionOnClassConditionOnWebApplicationCondition 继承该抽象类,实现 getOutcomes 方法,完成实际的过滤匹配操作。

本篇,我们就从源码入手重点介绍 FilteringSpringBootCondition

1. match 方法

上一篇博文我们已经从 FilteringSpringBootCondition 的部分源码进行了分析,它的 match 方法主要是调用 getOutcomes 方法,并将其返回的结果转换成布尔数组。而这个 getOutcomes 方法是过滤匹配的核心功能,由抽象类 FilteringSpringBootCondition 的子类来实现它。

这里再简单回顾一下 match 方法的处理逻辑:

@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
	ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
	// 调用 由子类实现的 getOutcomes 方法,完成实际的过滤匹配操作
	ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
	boolean[] match = new boolean[outcomes.length];
	// 将 getOutcomes 方法返回结果转换成布尔数组
	for (int i = 0; i < outcomes.length; i++) {
		match[i] = (outcomes[i] == null || outcomes[i].isMatch());
		if (!match[i] && outcomes[i] != null) {
			logOutcome(autoConfigurationClasses[i], outcomes[i]);
			if (report != null) {
				report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
			}
		}
	}
	return match;
}

上述代码中,我们可以看到,将 getOutcomes 方法返回结果转换成布尔数组的循环逻辑中有一段代码如下:

match[i] = (outcomes[i] == null || outcomes[i].isMatch());

这里是将返回结果转换成布尔值,分别是:

  • 如果匹配结果为 null ,认为符合匹配要求, 设置 match[i] = true
  • 如果匹配结果不为 null,并且 匹配对象的 isMatch == true,也认为符合匹配要求, 设置 match[i] = true

这个时候,我们就能理解 上篇博文讲到的 不符合过滤匹配要求,则清空当前的自动配置组件 的逻辑:
在这里插入图片描述

当然 FilteringSpringBootCondition 内还有其他的内容,这些内容在它的子类中也将使用到,我们先提前了解下,以便后续能更好地理解子类的功能实现。

2. ClassNameFilter 枚举类

首先查看 ClassNameFilter 枚举类的源码【Spring Boot 2.7.9】:

protected enum ClassNameFilter {

	PRESENT {

		@Override
		public boolean matches(String className, ClassLoader classLoader) {
			return isPresent(className, classLoader);
		}

	},

	MISSING {

		@Override
		public boolean matches(String className, ClassLoader classLoader) {
			return !isPresent(className, classLoader);
		}

	};

	abstract boolean matches(String className, ClassLoader classLoader);

	// ....

}

ClassNameFilter 枚举类包含两个枚举常量,分别是 PRESENTMISSING;这两个枚举常量都实现了 ClassNameFilter 枚举类定义的 matches 的抽象方法,其中

  • PRESENT 中的 matches 返回 isPresent(className, classLoader);
  • MISSING 中的 matches 返回 !isPresent(className, classLoader);

我们继续看 isPresent 方法,分析一下它的功能:

static boolean isPresent(String className, ClassLoader classLoader) {
	if (classLoader == null) {
		classLoader = ClassUtils.getDefaultClassLoader();
	}
	try {
		resolve(className, classLoader);
		return true;
	}
	catch (Throwable ex) {
		return false;
	}
}

protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
	if (classLoader != null) {
		return Class.forName(className, false, classLoader);
	}
	return Class.forName(className);
}

上述 isPresent 方法的逻辑其实也并不复杂,就是通过类加载器去加载指定的类【即 className 字符串对应的类】:

  • 如果指定的类加载成功,则直接返回 true
  • 如果指定的类加载失败,则要抛出异常,捕获异常后,返回 false

那显然 ClassNameFilter.PRESENT.matches(className, classLoader) 用于校验指定的类是否加载成功

  • 如果指定的类加载成功,则返回 true
  • 如果指定的类加载失败,则返回 false

ClassNameFilter.MISSING.matches(className, classLoader) 用于校验指定的类是否加载失败

  • 如果指定的类加载失败,则返回 true
  • 如果指定的类加载成功,则返回 false

3. filter 方法

继续翻看 FilteringSpringBootCondition 源码,还有一个 filter 方法需要重点介绍下:

protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter, ClassLoader classLoader) {
	if (CollectionUtils.isEmpty(classNames)) {
		return Collections.emptyList();
	}
	List<String> matches = new ArrayList<>(classNames.size());
	for (String candidate : classNames) {
		if (classNameFilter.matches(candidate, classLoader)) {
			matches.add(candidate);-
		}
	}
	return matches;
}

结合上面的 ClassNameFilter 枚举类,我们可以很容易理解上面的代码逻辑。

  • 如果 classNameFilterClassNameFilter.PRESENT,则 filter 方法获取指定的类集合中加载成功的类集合【即匹配成功的类集合】;
  • 如果 classNameFilterClassNameFilter.MISSING,则 filter 方法获取指定的类集合中加载失败的类集合【即匹配失败的类集合】。

总结

本篇 Huazie 带大家介绍了自动配置过滤匹配的核心父类 FilteringSpringBootCondition,这对于笔者后续博文详解它的三个子类【OnBeanConditionOnClassConditionOnWebApplicationCondition】非常重要,敬请期待!!!。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Spring Boot 源码学习】深入 FilteringSpringBootCondition 的相关文章

  • 设置Crontab执行任务时不发送邮件

    crontab的定时任务执行后都会给root发送一封邮件 通过以下方法可以防止这种情况 SHELL bin bash PATH sbin bin usr sbin usr bin 这是第一种方法 设置MAILTO参数为空 MAILTO HO
  • 微信网页版接口详解

    一 网页版微信提供的HTTP接口 1 获取uuid 说明 用于获取显示二维码以及登录所需的uuid 标识获取二维码和扫码的为同一个用户 请求方式 GET 地址 https login wx qq com jslogin get参数 参数 示
  • WSL安装及部分报错

    WSL安装 成功过程 错误示范 第一次进行操作时 第二次安装wsl 成功过程 结合使用了微软商城的评论区的建议 在链接https wsldownload azureedge net Ubuntu 2004 2020 424 0 x64 ap
  • JAVA语言中“+”号的三种用法

    一 数字相加 当 号两边都是数字时 代表数字相加 例如 int a 1 2 a的值为3 二 字符串连接 当 号两边至少有一个是字符串时 代表字符串连接 例如 String str hello world str的值为 helloworld

随机推荐

  • 如何使用Mac终端给树莓派pico构建C/C++程序进行开发,以及遇到各种问题该怎么处理,不使用任何IDE或编辑器(例如VS Code)

    写本文的原因是官方的教程已经过时了 如果你现在按照官方教程来在 Mac 上进行配置 那么会遇到一堆问题 比如我几乎把能踩的 雷 都踩了 所以这里记录了完整过程 以及各种错误的原因和处理方法 不然以后换 Mac 了或者在其他平台遇到同样的问题
  • 以太坊json rpc

    Contents Hash List JSON RPC support HEX value encoding The default block parameter Curl Examples Explained JSON RPC meth
  • HCIP-DATACOM-带解析-101-150题(821)

    101 VRP平台上 当我们引入OSPF路由到ISIS的时候 如果不指定COST 开销值将默认设为16 A 正确 B 错误 正确答案 B 答案解析 102 使用如下IP前缀列表进行路由匹配 则以下哪项路由可以被匹配到 ip ip prefi
  • 【Python】Python元组学习

    Python之元组学习记录 一 元组的特点 可以容纳多个数据 可以容纳不同类型的数据 混装 数据是有序存储的 下标索引 允许重复数据存在 不可以修改 增加或删除元素等 但内部list元素可以被修改 支持while for循环 二 元组操作练
  • [现代控制理论]4_PhasePortrait爱情故事动态系统分析

    现代控制理论 11 现代控制理论串讲 完结 pdf获取 现代控制理论 10 可观测性与分离原理 观测器与控制器 现代控制理论 9 状态观测器设计 龙伯格观测器 现代控制理论 8 5 线性控制器设计 轨迹跟踪simulink 现代控制理论 8
  • QFileDialog 对话框类

    QFileDialog 对话框类 QFileDialog 对话框类是 QDialog 类的子类 通过这个类可以选择要打开 保存的文件或者目录 关于这个类我们只需要掌握一些静态方法的使用就可以了 通用参数 parent 当前对话框窗口的父对象
  • Navicat导出整个数据库

    Navicat使用 转存为SQL文件的方式导出数据库 如果有外键会导致在导入时出错 需使用数据传输的方式进行导出 选成使用文件方式进行保存 高级选项需选成 这样导出的SQL脚本就是完整版本的 在新数据库中导入不般不会报错 如果出现导入报错
  • MySQL国内镜像

    一 基础概念 MySQL是一种关系型数据库管理系统 使用标准SQL查询语句进行数据访问 广泛应用于Web系统的数据存储 MySQL国内镜像指的是在国内建立的MySQL镜像站点 用于提供MySQL的各种资源下载和服务 由于MySQL在国内访问
  • A *p=new B;

    好久没有摸c 了 刚刚看到个面试题 发现都要忘了 巩固下 A P new B A是父类 B是子类 虽然P是一个基类的指针 但是new B调用的是派生类B的构造方法 所以构造的是B类对象 先调用A的构造函数 再调用B的构造函数 构造完后会返回
  • 【计算机操作系统】第一章、操作系统引论

    参考书籍为汤老师经典教材 本博客旨在作为自己学习笔记并与大家分享 1 操作系统的目标和作用 1 1 目标 方便 有效 可扩充 开放性 1 2 作用 作为用户和计算机硬件系统之间的接口 用户可以通过1 命令方式2 系统调用方式3 图形 窗口方
  • 生产环境数据库版本太低导致:PostgreSQL - ERROR: could not determine data type of parameter $1

    1 分析 这个问题一般值前端传回来的参数和实体类或者数据库不匹配 2 报错的sql LIKE CONCAT query areaName 3 报错问题 PostgreSQL ERROR could not determine data ty
  • C++不定参数个数函数的写法

    C 不定参数个数的函数比较常见 比如printf 先写一个字符串 在字符串里有0个或多个 每个 要对应后面一个数据或者字符之类的东西 理论上有多少个 都是没问题的 难不成还要搞几亿个printf的重载吗 nonono 这个时候就要用到C 一
  • html实训报告致谢,学术论文致谢词范文

    学术论文致谢篇一 行文至此 不仅意味着我研究生学习阶段的结束 而且也意味着我接受正式教育的结束 此刻我心中百感交集 焦虑 喜悦 失落 激动 时间如白驹过隙 往往在你来不及回味之时 就已经匆匆流逝 开学的那个瞬间仍然历历在目 它仿佛就在昨天
  • 场景间切换与数据传递(以及物体删除技巧)

    先介绍一些基本函数 具体用法自己查文档 1 场景切换 Application LoadLevel Level1 2 读取场景时不移除物体 DontDestroyOnLoad object 会保留该物体的任何数据 包括坐标 可以用于任何物体
  • vue中使用three,绘制3d场景--给模型增加文字标签

    上一篇文章链接 点这里 完整代码点这里 实际需求中 模型总会有一个文字标签 解释模型相关的信息 这里要用到的是 精灵平面 Sprite 精灵平面 Sprite 是一个在3D场景中总是面对着相机的平面 也就是无论你怎么旋转 你会发现他都朝向你
  • Python + Jenkins + Selenium-Grid实现分布式web-ui自动化测试(centos+win10为例)

    简介 Selenium分布式运行 SeleniumGrid 环境配置 jenkins win10 ip 100 100 100 101 selenium hub win10 ip 100 100 100 101 selenium node1
  • R语言—数组

    文章目录 数组 数组的生成 array 使用dim函数生成数组 多维数组的子集操作 数组 向量是1维数组 矩阵是二维数组 数组的维数可以大于2 数组的生成 array 格式 数组名 lt array 数组元素 dim c 第一下标个数 第二
  • 桂林电子科技大学校园网自动登录

    桂电的校园网自动登录十分十分十分简单 1 原理 懒得说原理 2 步骤 网上有 3 结论和方法 1 结论 直接访问特定的url就能登录了 这里给出校园网登录的和联通的url 校园网url http 10 0 1 5 drcom login c
  • 【源码+文档】数据库设计医药销售管理系统之Java

    开发环境和开发工具 操作系统 win8 1 开发环境 Mysql Web 开发工具 Workbench Eclipse JDBC 功能需求分析 员工有权查看 添加会员 查看 添加供应商 查询药品 输入药品编号或名称 类别等查询该药品或该类药
  • 【Spring Boot 源码学习】深入 FilteringSpringBootCondition

    Spring Boot 源码学习系列 深入 FilteringSpringBootCondition 引言 往期内容 主要内容 1 match 方法 2 ClassNameFilter 枚举类 3 filter 方法 总结 引言 前两篇博文