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

【Spring Boot 源码学习】走近 AutoConfigurationImportSelector

AutoConfigurationImportSelector 源码解析

  • 引言
  • 主要内容
    • 1. ImportSelector 接口
    • 2. DeferredImportSelector 接口
    • 3. AutoConfigurationImportSelector 功能概述
  • 总结

引言

上篇博文我们了解了 @EnableAutoConfiguration 注解,其中真正实现自动配置功能的核心实现者 AutoConfigurationImportSelector 还没有详细说明,本篇将从它的源码入手来重点介绍。

主要内容

在介绍 AutoConfigurationImportSelector 之前,有必要了解下它所实现的 ImportSelector 接口 ,如下所示:

1. ImportSelector 接口

在上篇博文中,我们介绍过 @Import 注解,它的许多功能其实是需要 ImportSelector 接口来实现,ImportSelector 接口决定可引入哪些 @Configuration

下面我们来看一下 ImportSelector 接口的源码【spring-context:5.3.25】:

/*** 实现了确定基于给定选择条件应该导入哪些 @Configuration 类的类型的接口,* 通常是一个或多个注解属性。* * 一个 ImportSelector 可以实现以下任意一个 Aware 接口,并在调用 selectImports * 方法之前调用其对应的方法:*    EnvironmentAware*    BeanFactoryAware*    BeanClassLoaderAware*    ResourceLoaderAware* * 另外,该类也可以提供一个带有以下支持的参数类型的单个构造函数:*    Environment*    BeanFactory*    ClassLoader*    ResourceLoader* * ImportSelector 实现通常与普通的 @Import 注解一样进行处理。* 然而,还可以推迟选择要导入的内容,直到所有 @Configuration * 类都被处理完毕(详见 DeferredImportSelector)。**/
public interface ImportSelector {/*** 根据导入的 @Configuration 类的 AnnotationMetadata(注解元数据),* 选择并返回应该导入的类名称。* * @return 返回类名的数组,如果没有则返回空数组。*/String[] selectImports(AnnotationMetadata importingClassMetadata);/*** 返回一个用于从导入的候选类中排除类的断言函数,* 该函数会递归地应用于通过此选择器的导入项找到的所有类。* * 如果对于给定的完全限定类名,该断言函数返回 true,* 则该类将不被视为被导入的配置类,从而跳过类文件加载和元数据检查。* * @return 返回一个用于完全限定的候选类名的筛选断言函数,该函数适用于递归导入的配置类。* 如果没有筛选断言函数,则返回 null。* @since 5.2.4*/@Nullabledefault Predicate<String> getExclusionFilter() {return null;}}

通过阅读上述源码,我们可以看到 ImportSelector 接口提供了一个参数为 AnnotationMetadata【它里面包含了被 @Import 注解的类的注解信息,即注解元数据】 的方法 selectImports ,并返回了一个字符串数组【可以根据具体实现决定返回哪些配置类的全限定名】。

源码注释里也提到了,如果我们实现了 ImportSelector 接口的同时又实现了以下的 4Aware 接口,那么 Spring 保证在调用 ImportSelector 之前会先调用 Aware 接口的方法。

这 4 个 Aware 接口分别是:

  • EnvironmentAware
  • BeanFactoryAware
  • BeanClassLoaderAware
  • ResourceLoaderAware

我们本篇要重点进行源码解析的 AutoConfigurationImportSelector 就实现了上述 4Aware 接口,部分源码如下所示:

// 其他导入语句省略
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.Ordered;/*** DeferredImportSelector 用于处理自动配置的延迟导入选择器。* 如果需要自定义的 @EnableAutoConfiguration 变体,也可以通过继承这个类来实现。*/
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {// 其他省略
}

从上面的 类定义中,我们可以看到 AutoConfigurationImportSelector 并没有直接实现 ImportSelector 接口,而是实现了 DeferredImportSelector 接口【它是 ImportSelector 的子接口 】。

2. DeferredImportSelector 接口

AutoConfigurationImportSelector 为啥不直接实现 ImportSelector 接口,而是实现了 DeferredImportSelector 接口呢?它们俩有什么区别呢?

在讲解清楚之前,我们先来看看 DeferredImportSelector 接口的源码【spring-context:5.3.25】:

/*** 一种在所有 @Configuration bean 处理完毕后运行的 ImportSelector 变体。* 这种类型的选择器在所选的导入项带有条件时特别有用。* * 实现类可以扩展 org.springframework.core.Ordered 接口或使用 * org.springframework.core.annotation.Order 注解来指定与* 其他 DeferredImportSelectors 的优先级。* * 实现类还可以提供一个导入组(import group),* 它可以在不同的选择器之间提供额外的排序和过滤逻辑。*/
public interface DeferredImportSelector extends ImportSelector {/*** 返回一个特定的导入组。* 默认实现会在不需要分组的情况下返回 null。* * @return 导入组的类,如果没有则返回 null。* @since 5.0*/@Nullabledefault Class<? extends Group> getImportGroup() {return null;}/*** 用于将来自不同导入选择器的结果进行分组的接口。* * @since 5.0*/interface Group {/*** 使用指定的 DeferredImportSelector 处理导入的 @Configuration 类的 AnnotationMetadata。*/void process(AnnotationMetadata metadata, DeferredImportSelector selector);/*** 返回此组应该导入的类的条目*/Iterable<Entry> selectImports();/*** 一个条目,包含导入的配置类的 AnnotationMetadata 和要导入的类名。*/class Entry {private final AnnotationMetadata metadata;private final String importClassName;public Entry(AnnotationMetadata metadata, String importClassName) {this.metadata = metadata;this.importClassName = importClassName;}/*** 返回导入的配置类的 AnnotationMetadata【注解元数据】*/public AnnotationMetadata getMetadata() {return this.metadata;}/*** 返回要导入的类的完全限定名称。*/public String getImportClassName() {return this.importClassName;}// 省略。。。}}}

通过阅读上述源码,可以了解到之所以 AutoConfigurationImportSelector 没有直接实现 ImportSelector 接口,而是实现了 DeferredImportSelector 接口,是因为通过DeferredImportSelector 接口能够在处理自动配置时,拥有更高的灵活性和可定制性。

总结来讲,它们的区别主要是如下几个方面:

  • 延迟导入DeferredImportSelector 具有延迟导入的能力,可以在所有的 @Configuration 类都被处理完毕之后再进行选择和导入。这样可以在整个配置加载过程完成后再根据某些条件或规则来决定要导入哪些类,从而实现更加动态和灵活的自动配置机制。

  • 筛选导入DeferredImportSelector 提供了一个用于筛选候选类名的断言函数,可以根据一定的条件来排除某些类的导入。这样可以对自动配置的候选类进行进一步的过滤和控制,使得只有符合特定条件的类才会被真正导入。

  • 自定义扩展:通过实现 DeferredImportSelector 接口,开发人员可以更方便地扩展和定制自动配置逻辑。可以根据实际需求重写相应方法,实现自定义的自动配置规则和行为。

上述源码注释中,也说明了 DeferredImportSelector 的加载顺序可以通过 @Order 注解 或 实现 Ordered 接口来指定。它还可以提供一个导入组,实现在不同的选择器之间提供额外的排序和过滤逻辑,从而实现自定义 Configuration 的加载顺序。

3. AutoConfigurationImportSelector 功能概述

好了到这里,我们终于可以开始正式介绍 AutoConfigurationImportSelector 了。

下面我们通过如下的流程图,从整体上来了解 AutoConfigurationImportSelector 的核心功能及流程【其中省略了外部通过 @Import 注解调用该类的部分】:

在这里插入图片描述

AutoConfigurationImportSelector 被 @Import 注解引入之后,它的 selectImports 方法会被调用并执行其实现的自动装配逻辑。

下面我们来看看 selectImports 方法的源码,如下所示:

	@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {// 检查自动配置功能是否开启,默认为开启if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}// 封装将被引入的自动配置信息AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);// 返回符合条件的配置类的全限定名数组return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}/*** 根据导入@Configuration类的AnnotationMetadata返回AutoConfigurationImportSelector.AutoConfigurationEntry。* @param 配置类的注解元数据。* @return 应该导入的自动配置。*/protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}// 从AnnotationMetadata返回适当的AnnotationAttributes。默认情况下,此方法将返回getAnnotationClass()的属性。AnnotationAttributes attributes = getAttributes(annotationMetadata);// 通过 SpringFactoriesLoader 类提供的方法加载类路径中META-INF目录下的// spring.factories文件中针对 EnableAutoConfiguration 的注解配置类List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 对获得的注解配置类集合进行去重处理,防止多个项目引入同样的配置类configurations = removeDuplicates(configurations);// 获得注解中被 exclude 或 excludeName 所排除的类的集合Set<String> exclusions = getExclusions(annotationMetadata, attributes);// 检查被排除类是否可实例化,是否被自动注册配置所使用,不符合条件则抛出异常checkExcludedClasses(configurations, exclusions);// 从自动配置类集合中去除被排除的类configurations.removeAll(exclusions);// 检查配置类的注解是否符合 spring.factories 文件中 AutoConfigurationImportFilter 指定的注解检查条件configurations = getConfigurationClassFilter().filter(configurations);// 将筛选完成的配置类和排除的配置类构建为事件类,并传入监听器。监听器的配置在于 spring.factories 文件中,通过 AutoConfigurationImportListener 指定fireAutoConfigurationImportEvents(configurations, exclusions);// 创建并返回一个条目,其中包含了筛选完成的配置类和排除的配置return new AutoConfigurationEntry(configurations, exclusions);}

总结

通过阅读上述源码,对照相关的流程图,我们从整体上了解了 AutoConfigurationImportSelector 自动装配逻辑的核心功能及流程,由于篇幅有限,更加细化的功能及流程解析,笔者将在后续的博文中,带大家一起通过源码来一步步完成,敬请期待!!!

相关文章:

【Spring Boot 源码学习】走近 AutoConfigurationImportSelector

AutoConfigurationImportSelector 源码解析 引言主要内容1. ImportSelector 接口2. DeferredImportSelector 接口3. AutoConfigurationImportSelector 功能概述 总结 引言 上篇博文我们了解了 EnableAutoConfiguration 注解&#xff0c;其中真正实现自动配置功能的核心实现者 …...

系统学习Linux-MySQL数据库备份(四)

一、概述 数据库备份是指将数据库中的数据、表格、视图、存储过程、触发器等信息备份到另一个地方&#xff0c;一遍在数据库丢失或损坏时进行恢复&#xff0c;数据库备份是数据库管理中必不可少的一项工作&#xff0c;通过备份可以保护数据库中的数据和业务。 二、数据备份的…...

具身智能controller---RT-1(Robotics Transformer)(中---实验介绍)

6 实验 实验目的是验证以下几个问题: RT-1可以学习大规模指令数据&#xff0c;并且可以在新任务、对象和环境上实现zero-shot的泛化能力&#xff1f;训练好的模型可以进一步混合多种其他数据&#xff08;比如仿真数据和来自其他机器人的数据&#xff09;吗&#xff1f;多种方…...

无涯教程-jQuery - load( url, data, callback)方法函数

load(url&#xff0c;data&#xff0c;callback)方法从服务器加载数据&#xff0c;并将返回的HTML放入匹配的元素中。 load( url, [data], [callback] ) - 语法 [selector].load( url, [data], [callback] ) 这是此方法使用的所有参数的描述- url - 包含请求发送到…...

【Shell】Shell编程之免交互

免交互&#xff1a;不需要人为控制就可以完成的自动化操作 自动化运维 Shell脚本和免交互是一个概念&#xff0c;但是两种写法 here document 使用i/o重定向的方式将命令的列表提供给交互式的程序或者命令 是一种标准输入&#xff0c;只能接受正确的指令或命令&#x…...

从Vue2到Vue3【七】——Vue2中响应式原理的实现及其缺陷

系列文章目录 内容链接从Vue2到Vue3【零】Vue3简介从Vue2到Vue3【一】Composition API&#xff08;第一章&#xff09;从Vue2到Vue3【二】Composition API&#xff08;第二章&#xff09;从Vue2到Vue3【三】Composition API&#xff08;第三章&#xff09;从Vue2到Vue3【四】C…...

用C语言实现堆排序算法

1.设计思路 排序的思想将一个数组按递增的顺序进行排序&#xff0c;将数组的第一个位置空下&#xff08;下标为0&#xff09;&#xff0c;因为会导致子节点和本身同一个结点&#xff08;i和2i一致&#xff09;&#xff0c;每次堆排序在下标1的位置放上了最大值&#xff0c;然后…...

tauri在github上进行自动更新打包并发版过程,实战操作避坑

从网上找了很多很多的文章&#xff0c;结果还是入坑了&#xff0c;一个问题找了一天才解决&#xff1a; Error A public key has been found, but no private key. Make sure to set TAURI_PRIVATE_KEY environment variable. 596 ELIFECYCLE  Command failed with exit code…...

css中flex后文本溢出的问题

原因&#xff1a; 为了给flex item提供一个合理的默认最小尺寸&#xff0c;flex将flex item的min-width 和 min-height属性设置为了auto flex item的默认设置为&#xff1a; min-width&#xff1a; auto 水平flex布局 min-height&#xff1a;auto 垂直flex布局 解决办法&…...

restful接口设计规范[仅供参考]

1. 域名 应该尽量将API部署在专用域名之下。 https://api.example.com 如果确定API很简单&#xff0c;不会有进一步扩展&#xff0c;可以考虑放在主域名下。 https://www.example.org/api/2. 版本&#xff08;Versioning&#xff09; 应该将API的版本号放入URL。 http://…...

Metabase 远程代码执行(CVE-2023-38646)

漏洞描述 Metabase是一款开源数据分析及可视化工具。它可允许用户连接至各种不同类型数据源,未经身份认证的攻击者可利用本漏洞在服务器上以运行 Metabase服务器的权限进行任意命令执行。 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩…...

【TiDB理论知识 07】SQL执行流程

一 DML语句读写流程 1 DML语句读流程概要 用户发出SQL 被协议层接收 Protocal Layer 通过PD获取时间戳 parse模块 解析SQL&#xff0c;通过词法解析 与 语法解析 生成AST语法树 编译SQL Compile模块 ,区分点查 与 非点查&#xff0c;生成执行计划 发送给Executor,从TIKV获…...

微服务——服务异步通讯RabbitMQ

前置文章 消息队列——RabbitMQ基本概念容器化部署和简单工作模式程序_北岭山脚鼠鼠的博客-CSDN博客 消息队列——rabbitmq的不同工作模式_北岭山脚鼠鼠的博客-CSDN博客 消息队列——spring和springboot整合rabbitmq_北岭山脚鼠鼠的博客-CSDN博客 目录 Work queues 工作队列…...

事件冒泡、事件捕获和事件委托

原文合集地址如下&#xff0c;有需要的朋友可以关注 本文地址 合集地址 什么是事件冒泡、事件捕获和事件委托&#xff1f; 事件冒泡&#xff08;Event Bubbling&#xff09;、事件捕获&#xff08;Event Capturing&#xff09;和事件委托&#xff08;Event Delegation&…...

WEB 典型安全功能说明

WEB 典型安全功能 认证Authentication 认证是指通过验证用户的身份来确认用户是否有权访问某个系统或资源。在Web安全中&#xff0c;认证是非常重要的一环&#xff0c;它可以防止未经授权的访问&#xff0c;保护用户的数据和系统的安全。 登录 登录是用户认证的常见方式之一…...

SQL编译优化原理

最近在团队的OLAP引擎上做了一些SQL编译优化的工作&#xff0c;整理到了语雀上&#xff0c;也顺便发在博客上了。SQL编译优化理论并不复杂&#xff0c;只需要掌握一些关系代数的基础就比较好理解&#xff1b;比较困难的在于reorder算法部分。 文章目录 基础概念关系代数等价 j…...

qt signal slots lambda

这里用到了qt的版本检测 连接 Combox的currentIndexChanged事件 emit来触发处理的事件 &#xff0c;进行业务或逻辑处理 这样的写法是lambda表达式的写法&#xff0c;和c#中的 (obj)>{ //todo } 类同 [](int indx){ //todo } #if QT_VERSION > QT_VERSION_CHECK(5,7,0)c…...

Spring【声明式事务】

事务简介 把一组业务当成一个业务来做&#xff1b;要么都成功&#xff0c;要么都失败&#xff01;事务在项目开发中&#xff0c;十分重要&#xff0c;涉及到数据一致性的问题&#xff0c;需要十分注意&#xff01;确保完整性和一致性&#xff01; 事务的ACID原则&#xff1a;…...

【雕爷学编程】MicroPython动手做(17)——掌控板之触摸引脚2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…...

pytorch 中 view 和reshape的区别

在 PyTorch&#xff08;一个流行的深度学习框架&#xff09;中&#xff0c; reshape 和 view 都是用于改变张量&#xff08;tensor&#xff09;形状的方法&#xff0c;但它们在实现方式和使用上有一些区别。下面是它们之间的主要区别&#xff1a; 实现方式&#xff1a; reshap…...

3个颠覆性技巧:重新定义现代界面字体的选择标准

3个颠覆性技巧&#xff1a;重新定义现代界面字体的选择标准 【免费下载链接】source-sans Sans serif font family for user interface environments 项目地址: https://gitcode.com/gh_mirrors/so/source-sans 你是否曾为网页上的文字不够清晰而烦恼&#xff1f;或是发…...

CharacterAI Python API终极指南:如何快速构建AI对话机器人

CharacterAI Python API终极指南&#xff1a;如何快速构建AI对话机器人 【免费下载链接】CharacterAI Unofficial Python API for character.ai 项目地址: https://gitcode.com/gh_mirrors/ch/CharacterAI 你是否想在自己的Python应用中集成CharacterAI的强大对话功能&a…...

PDF补丁丁终极指南:5分钟学会PDF元数据精准修改技巧

PDF补丁丁终极指南&#xff1a;5分钟学会PDF元数据精准修改技巧 【免费下载链接】PDFPatcher PDF补丁丁——PDF工具箱&#xff0c;可以编辑书签、剪裁旋转页面、解除限制、提取或合并文档&#xff0c;探查文档结构&#xff0c;提取图片、转成图片等等 项目地址: https://gitc…...

为什么公平感比财富本身更影响希望

有些时刻&#xff0c;普通人最难受的不是自己暂时没钱。而是你发现&#xff0c;自己已经很努力地排队、提交材料、遵守规则、等待结果&#xff0c;可最后还是不知道机会到底怎么分配。 孩子上学&#xff0c;要反复比较资源差异。 老人看病&#xff0c;要担心排队、费用和后续照…...

JMeter压测秒退的三大静默杀手:线程组、超时、监听器

1. 这不是JMeter“崩了”&#xff0c;而是它在用报错告诉你&#xff1a;配置里藏着三个沉默的杀手 刚跑完第一个JMeter压测脚本&#xff0c;线程组设了200个用户、持续5分钟&#xff0c;结果3秒后就自动停了——控制台只留下一行灰底白字的 INFO o.a.j.e.StandardJMeterEngine…...

揭秘K12课堂AI转型真相:3个被90%学校忽略的PlayAI部署陷阱及72小时应急修复指南

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;PlayAI教育领域应用案例 PlayAI 作为面向教育场景的轻量级AI交互平台&#xff0c;已在多个教学实践中展现出显著的适配性与可扩展性。其核心优势在于无需深度编程基础即可构建个性化学习路径、实时学情…...

STM32CubeMX配置SPI驱动W25Q128实战:从硬件连接到DMA优化(附完整代码)

STM32CubeMX配置SPI驱动W25Q128实战&#xff1a;从硬件连接到DMA优化 在嵌入式开发中&#xff0c;SPI接口的Flash存储器因其高速、简单和可靠的特点&#xff0c;成为存储配置数据、日志和固件的理想选择。W25Q128作为Winbond公司推出的128Mbit串行Flash存储器&#xff0c;广泛…...

Anthropic Zero Layer:大模型推理栈的原子化归一

1. 项目概述&#xff1a;这不是一次普通更新&#xff0c;而是一次架构级“蒸发” “Anthropic Just Shipped the Layer That’s Already Going to Zero”——这个标题乍看像科技媒体的夸张头条&#xff0c;但作为连续跟踪Claude模型演进三年、亲手部署过从Haiku到Sonnet再到Opu…...

TPT线下工作坊:AIGC、云原生与数据合规的深度实践与碰撞

1. 活动缘起与核心价值&#xff1a;为什么一场线下工作坊如此重要&#xff1f;在数字营销和内容创作领域&#xff0c;我们每天都被海量的线上信息包围。线上会议、直播、社群讨论&#xff0c;这些形式高效且便捷&#xff0c;但总感觉隔着一层屏幕&#xff0c;少了些温度与深度。…...

学网安压根不卡学历,在校生自学这样走少绕好几年弯路

学网安压根不卡学历&#xff0c;在校生自学这样走少绕好几年弯路 前言 “网络安全只有计算机高材生才能学&#xff1f;” “没有名校背景&#xff0c;根本进不了这个行业&#xff1f;” “普通专科生、本科生、非科班出身想要自学网络安全&#xff0c;难度太大了吧&#xf…...