SpringBoot自动装配的原理

废话不多说,直接上干货

 SpringBoot 是如何实现自动装配的?

以我这个2.6.13的版本为例

第一步,我们先从@SpringBootApplication这个入口注解看起

在springBootApplication这个注解当中有三个关键性的注解,大概可以看作是:

1,@SpringBootConfiguration        声明是个配置类
2,@EnableAutoConfiguration        负责自动配置
3,@ComponentScan                  负责包扫描

我们的重点是@EnableAutoConfiguration,因为这个才是负责spring的自动配置,

第二步,我们进入@EnableAutoConfiguration这个注解中:

@Import(AutoConfigurationImportSelector.class)这行代码是重点!

第三步,我们打开AutoConfigurationImportSelector这个类

能看到这个类实现了DeferredImportSelector接口(延迟加载的功能,也就是等其他bean定义之后来

注意:DeferredImportSelector是ImportSelector的子接口,里面有一个selectImports的方法

这个方法中的importingClassMetadata参数能拿到类上注解的信息,比如读取注解的名称、属性值等信息。

第四步,我们来到 AutoConfigurationImportSelector类的selectImports方法

@Override
/*** 决定哪些自动配置类应该被导入到Spring应用程序中。* @param annotationMetadata 当前正在处理的配置类的注解元数据。* @return 一个字符串数组,包含了应该被导入的自动配置类的全限定类名。*/
public String[] selectImports(AnnotationMetadata annotationMetadata) {// 检查是否应该启用自动配置。这通常基于特定的条件,比如类上的注解。if (!isEnabled(annotationMetadata)) {// 如果自动配置未启用,返回一个空数组,表示没有配置类需要被导入。return NO_IMPORTS;}// 获取自动配置条目,这包含了应该被导入的配置类的信息。// 这个方法会根据注解元数据和其他条件来确定这些配置类。AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);// 将配置类的列表转换为字符串数组。这是为了满足selectImports方法的返回类型要求。// StringUtils.toStringArray方法将List<String>转换为String[]。return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

第五步,我们进入getAutoConfigurationEntry这个方法

这才是自动装配的根源,接下来我们一行一行来解读

跟着我的解读,自己可以Debug一步一步看,效果会更好!

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes = getAttributes(annotationMetadata);List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);configurations = removeDuplicates(configurations);Set<String> exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = getConfigurationClassFilter().filter(configurations);fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}

下面是这个方法中每个步骤的详细解释:

1. **检查是否启用自动配置**:
   if (!isEnabled(annotationMetadata)) {
       return EMPTY_ENTRY;
   }
这一步检查是否应该启用自动配置。`isEnabled` 方法可能会检查类上的注解(如 `@EnableAutoConfiguration`)或者类路径上的条件来决定是否启用。如果不启用,就返回一个空的 `AutoConfigurationEntry` 对象。

2. **获取注解属性**:
   AnnotationAttributes attributes = getAttributes(annotationMetadata);


   这一步获取与自动配置相关的注解属性。这些属性可能包括 `@AutoConfiguration` 注解的属性,如 `exclude` 和 `excludeName`,它们用于指定应该排除哪些自动配置类。

3. **获取候选配置**:
   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);


   获取需要自动装配的所有配置类,读取META-INF/spring.factories文件,Spring Boot Starter 下的META-INF/spring.factories都会被读取到。

4. **去重**:
   configurations = removeDuplicates(configurations);


   这一步确保候选配置列表中没有重复的类名。这通常通过创建一个新的集合来实现,只包含之前列表中未出现过的类名。

5. **获取排除的配置**:
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);


   这一步根据注解属性(如 `exclude`)获取需要排除的自动配置类的集合。

6. **检查排除的类**:
   checkExcludedClasses(configurations, exclusions);


   这一步检查排除的类是否在候选配置列表中。如果不在,可能意味着排除逻辑有误,或者是一个bug。

7. **移除排除的配置**:
   configurations.removeAll(exclusions);


   这一步从候选配置列表中移除所有在排除集合中的类名。

8. **过滤配置类**:
   configurations = getConfigurationClassFilter().filter(configurations);


   这一步使用 `ConfigurationClassFilter` 对候选配置列表进行过滤。这个过滤器可以根据@ConditionalOnxxx相关的注解,来决定哪些类应该被包含

9. **触发自动配置导入事件**:
   fireAutoConfigurationImportEvents(configurations, exclusions);


   这一步触发Spring的自动配置导入事件,允许其他组件(如监听器)在自动配置类被确定之前进行干预。

10. **创建并返回AutoConfigurationEntry对象**:
    return new AutoConfigurationEntry(configurations, exclusions);


    最后,这个方法创建一个 `AutoConfigurationEntry` 对象,它包含了最终确定的自动配置类列表和排除的类列表,并返回这个对象。这个对象随后会被Spring Boot用来加载和应用自动配置。

总的来说,这个方法是Spring Boot自动配置流程的核心部分,它负责确定哪些自动配置类应该被加载,以及哪些应该被排除。这个过程涉及到注解解析、条件检查、去重、过滤等多个步骤,以确保自动配置既准确又高效。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

286.【华为OD机试真题】学生重新排队(JavaPythonC++JS实现)

🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目-学生重新排队二.解题思路三.题解代码Python题解…

[回溯]组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被选取 。如…

Java面试:Spring Cloud Alibaba

文章目录 引言I Spring Cloud Alibaba1.1 配置文件加载的优先级(由高到低)1.2 注册中心1.3 rpcII 高并发场景:缓存穿透/缓存失效/雪崩如何解决2.1 缓存穿透2.2 缓存击穿(失效)2.3 缓存雪崩引言 微服务涉及的中间件分布式事务事务的传播方式事务的隔离级别缓存穿透/缓存失效…

Matlab/simulink基于vsg的风光储调频系统建模仿真(持续更新)

​ 1.Matlab/simulink基于vsg的风光储调频系统建模仿真&#xff08;持续更新&#xff09;

掘根宝典之C语言基本数据类型详解1——整型介绍,整数溢出,大小端,整型常量的存储,整型提升

目录 基本数据类型的介绍 类型的意义 修饰符类型&#xff1a; 整型数据类型 int&#xff1a; short int(通常写short)&#xff1a; long int(通常写long)&#xff1a; long long(通常写long long)&#xff1a; char 使用多种整数类型的原因 整型常量的存储 1.字面常…

C/C++暴力/枚举/穷举题目持续更新(刷蓝桥杯基础题的进!)

目录 前言 一、百钱买百鸡 二、百元兑钞 三、门牌号码&#xff08;蓝桥杯真题&#xff09; 四、相乘&#xff08;蓝桥杯真题&#xff09; 五、卡片拼数字&#xff08;蓝桥杯真题&#xff09; 六、货物摆放&#xff08;蓝桥杯真题&#xff09; 七、最短路径&#xff08;蓝…

图解目标检测 之 【YOLOv9】 算法 最全原理详解

YOLOv9与SOTA模型对比 什么是 YOLOv9&#xff1f;YOLOv9是YOLO系列中的最新产品&#xff0c;是一种实时目标检测模型。它通过先进的深度学习技术和架构设计&#xff0c;包括通用 ELAN (GELAN) 和可编程梯度信息 (PGI)&#xff0c;展现出更好的性能。 YOLO 系列通过引入计算机视…

Java/Python/Go不同开发语言基础数据结构和相关操作总结-GC篇

Java/Python/Go不同开发语言基础数据结构和相关操作总结 1. 常见gc方式1.1 gc判断对象是否存活1.2 引用计数法1.2 标记-清除算法1.3 复制算法1.4 标记-压缩算法1.5 分代收集算法 2. java的gc方式以及垃圾回收器2.1 gc方式2.1 gc回收器2.1.1 Serial收集器2.1.2 ParNew收集器2.1.…

防御第六次作业-笔记整理

目录 DPI DFI 签名 AV URL过滤 HTTPS过滤 文件内容过滤 VPN概述 密码学 对称加密 非对称加密 HASH运算 DPI DPI --- 深度包检测技术 --- 主要针对完整的数据包&#xff08;数据包分片&#xff0c;分段需要重组&#xff09;&#xff0c;之后对数据包的内容进行识别。…

Socket、UDP、TCP协议和简单实现基于UDP的客户端服务端

目录 Socket TCP和UDP区别 UDP&#xff1a;无连接&#xff0c;不可靠传输&#xff0c;面向数据报&#xff0c;全双工 TCP&#xff1a;有连接&#xff0c;可靠传输&#xff0c;面向字节流&#xff0c;全双工 无连接和有连接 可靠传输和不可靠传输 面向数据报和面向字节流…

学习或从事鸿蒙开发工作,有学历要求吗?

目前安卓有2,000万的开发者。本科及以上学历占比为35%&#xff1b;iOS有2,400万开发者&#xff0c;本科及以上学历占比为40% 绝大多数的前端开发者都是大专及以下学历&#xff0c;在2023年华为开发者大会上余承东透露华为的开发者目前有200万&#xff0c;但鸿蒙开发者统计的数据…

C#,数组数据波形排序(Sort in Wave Form)的朴素算法与源代码

1 波形排序 所谓“波形排序”就是一大一小。 将n个身高互不相同的人排成一行 ,对于每个人 ,要求他要么比相邻的人均高 ,要么比相邻的人均矮 ,问共有多少种排法 ,这一问题称为波形排列问题。 2 源程序 using System; using System.Collections; using System.Collections.Gen…

[嵌入式系统-33]:RT-Thread -18- 新手指南:三种不同的版本、三阶段学习路径

目录 前言&#xff1a;学习路径&#xff1a;入门学习-》进阶段学习》应用开发 一、RT-Thread版本 1.1 标准版 1.2 Nano 1.3 Smart版本 1.4 初学者制定学习路线 1.5 RT-Thread在线文档中心目录结构 1.6 学习和使用RT-Thread的三种场景 二、入门学习阶段&#xff1a;内…

Java SDK下沉:解决SDK治理痛点

痛点难点 在每个java应用中,都会存在各种各样的SDK,随着时间流逝和技术的迭代,SDK也需要进行相应的版本更新,在大型微服务系统中,动辄几百上千个应用,要推动这个数量级的应用进行SDK升级或者覆盖接入,消耗的成本是巨大的,这也是微服务治理的一大难点。 那么这个难点如…

信息系统项目管理师论文分享(质量管理)

水一篇文章。我发现身边考高项的朋友很多都是论文没过&#xff0c;我想着那就把我的论文分享出来&#xff0c;希望能有帮助。 质量管理 摘要 2020年5月&#xff0c;我作为项目经理参加了“某市某医联体的互联网诊疗&#xff08;互联网医院和远程医疗&#xff09;平台”的建设…

编程的基础:理解时间和空间复杂度

编程的基础&#xff1a;理解时间和空间复杂度 时间复杂度空间复杂度示例常数时间复杂度 O(1)线性时间复杂度 O(n)线性对数时间复杂度 O(n log n)二次时间复杂度 O(n^2)指数时间复杂度 O(2^n) 空间复杂度示例常数空间复杂度 O(1)线性空间复杂度 O(n)线性对数空间复杂度 O(log n)…

apache 模式、优化、功能 与 nginx优化、应用

一、I/O模型——Input/Output模型 1.同步/异步 A程序需要调用B程序的某一个功能&#xff0c;A发送一个请求需要B完成一个任务 同步&#xff1a;B不会主动去通知A是否完成需要A自己去问 异步&#xff1a;B会主动通知A是否完成 2.阻塞/非阻塞 A发送一个请求需要B完成一个任务 …

springboot接收base64文件并上传

1. 前言 在常见的开发场景中&#xff0c;前端往往对文件进行base64编码&#xff0c;采用 json 格式发送给后端&#xff0c;后端收到 base64文件的字符串后进行保存 实现步骤&#xff1a;后端直接通过 Base64工具类对字符串进行解码&#xff0c;解码后获取字节数组。将字节数组…

Vision Mamba:使用双向状态空间模型进行高效视觉表示学习

模型效果 将DeiT和Vim模型之间的性能和效率比较&#xff0c;为了进行准确性比较&#xff0c;我们首先在IN1K分类数据集上预训练DeiT和Vim&#xff0c;然后在不同的下游密集预测任务上微调通用主干&#xff0c;即&#xff0c;语义分割、目标检测、实例分割。结果表明&#xff0c…

Maven 私服 Nexus3

一、Maven和Nexus3 简介 Maven是一个采用纯Java编写的开源项目管理工具&#xff0c;采用一种被称之为Project Object Model(POM)概念来管理项目&#xff0c;所有的项目配置信息都被定义在一个叫做POM.xml的文件中, 通过该文件Maven可以管理项目的整个生命周期&#xff0c;包括…