【springboot】自动加载分析
文章目录
- 问题
- @SpringBootApplication注解
- AutoConfigurationPackages.Registrar类
- AutoConfigurationImportSelector类
- springboot如何加载其他的starter
- 总结
问题
为什么我们在使用springboot的时候,只需要在maven中导入starter就能够使用呢?这里来分析一下
@SpringBootApplication注解
这个注解一般用在springboot程序的主启动类上,这个注解除去元注解,由下面几个注解构成
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
@SpringBootConfiguration是由下面两个注解构成
@Configuration
@Indexed
@EnableAutoConfiguration是由下面内容构成
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage内容如下
@Import(AutoConfigurationPackages.Registrar.class)
所以@SpringBootApplication等价于下面内容
// @SpringBootConfiguration
@Configuration
@Indexed// @EnableAutoConfiguration
@Import(AutoConfigurationPackages.Registrar.class)
@Import(AutoConfigurationImportSelector.class)@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
可以发现实际就是导入了两个类,一个AutoConfigurationPackages.Registrar,一个AutoConfigurationImportSelector。
AutoConfigurationPackages.Registrar类
这个类的信息如下
/*** {@link ImportBeanDefinitionRegistrar} to store the base package from the importing* configuration.*/static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));}@Overridepublic Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new PackageImports(metadata));}}
作用就是获取要扫描的包路径
AutoConfigurationImportSelector类
这个类的内容如下

里面实现了多个接口以Aware结尾的接口,其实就是完成某种资源的设置,Ordered就是用于指定bean加载顺序的,最重要的是DeferredImportSelector,这个接口继承了ImportSelector,ImportSelector就可以完成bean的注入工作

这个接口里面的group类里面就包含了要进行加载的bean信息

回到实现类,也就是AutoConfigurationImportSelector,去到process方法
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,() -> String.format("Only %s implementations are supported, got %s",AutoConfigurationImportSelector.class.getSimpleName(),deferredImportSelector.getClass().getName()));AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);this.autoConfigurationEntries.add(autoConfigurationEntry);for (String importClassName : autoConfigurationEntry.getConfigurations()) {this.entries.putIfAbsent(importClassName, annotationMetadata);}
}
将这个方法分解一下
// 获取自动配置的类AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);// 遍历自动配置的beanfor (String importClassName : autoConfigurationEntry.getConfigurations()) {// 如果存在这个类就进行加入this.entries.putIfAbsent(importClassName, annotationMetadata);}
里面关键的就是获取所有的自动配置类,关键方法就是getAutoConfigurationEntry这个方法,进入这个方法
/*** Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}* of the importing {@link Configuration @Configuration} class.* @param annotationMetadata the annotation metadata of the configuration class* @return the auto-configurations that should be imported*/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);}
里面的关键语句就是
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
功能就是完成获取所有要进行自动加载的bean,进入到方法
/*** Return the auto-configuration class names that should be considered. By default* this method will load candidates using {@link ImportCandidates} with* {@link #getSpringFactoriesLoaderFactoryClass()}. For backward compatible reasons it* will also consider {@link SpringFactoriesLoader} with* {@link #getSpringFactoriesLoaderFactoryClass()}.* @param metadata the source metadata* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation* attributes}* @return a list of candidate configurations*/protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = new ArrayList<>(SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);Assert.notEmpty(configurations,"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations;}
这个方法里面的
List<String> configurations = new ArrayList<>(SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));

这个方法用于读取类路径下的所有 META-INF/spring.factories文件
下面的这行代码
ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
将其拆解为
ImportCandidates ic = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader());ic.forEach(configurations::add);
可以发现就是先去获取所有自动加载bean,然后将其加入到一个集合中,进入到load方法
/*** Loads the names of import candidates from the classpath.** The names of the import candidates are stored in files named* {@code META-INF/spring/full-qualified-annotation-name.imports} on the classpath.* Every line contains the full qualified name of the candidate class. Comments are* supported using the # character.* @param annotation annotation to load* @param classLoader class loader to use for loading* @return list of names of annotated classes*/public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {Assert.notNull(annotation, "'annotation' must not be null");ClassLoader classLoaderToUse = decideClassloader(classLoader);String location = String.format(LOCATION, annotation.getName());Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);List<String> importCandidates = new ArrayList<>();while (urls.hasMoreElements()) {URL url = urls.nextElement();importCandidates.addAll(readCandidateConfigurations(url));}return new ImportCandidates(importCandidates);}
里面最重要的语句就是
importCandidates.addAll(readCandidateConfigurations(url));
其实就是读取配置文件的信息,然后加入到集合中。读取的位置就是

META-INF/spring/%s.imports
实际上就是去读取


里面一共有144个默认加载项,然后再经过一些过滤操作,就会返回所有的配置类信息
/*** Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}* of the importing {@link Configuration @Configuration} class.* @param annotationMetadata the annotation metadata of the configuration class* @return the auto-configurations that should be imported*/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);}

后面springboot就会去处理这些这些配置类。
springboot如何加载其他的starter
其实上面已经说了,springboot会去读取类路径下的所有META-INF/spring.factories文件,所以只需要在这个文件中写上自动配置的类即可,以mybatis-plus为例子,如下

总结
springboot在启动的时候会去读取org\springframework\boot\spring-boot-autoconfigure\2.7.10\spring-boot-autoconfigure-2.7.10.jar!\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports这个文件中的所有配置。
springboot通过读取META-INF\spring.factories下的配置文件来支持其他starter的注入
相关文章:
【springboot】自动加载分析
文章目录问题SpringBootApplication注解AutoConfigurationPackages.Registrar类AutoConfigurationImportSelector类springboot如何加载其他的starter总结问题 为什么我们在使用springboot的时候,只需要在maven中导入starter就能够使用呢?这里来分析一下…...
ChatGPT批量翻译-ChatGPT批量生成多国语言
ChatGPT翻译的准吗 ChatGPT是一种基于Transformer架构的自然语言处理技术,其翻译准确性取决于所训练的模型和数据集的质量。在特定的语料库和训练数据下,ChatGPT可以实现一定程度的准确翻译。但是,与人工翻译相比,ChatGPT的翻译质…...
Symble
ES6引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。 Symbol特点 Symbol 的值是唯一的,用来解决命名冲突的问题 Symbol值不能与其他数据进行运算 Symbol定义的对…...
能在家里赚钱的工作有哪些?适合普通人的兼职项目
当下对于普通人而言,想在社会上找到一份舒心安逸的工作很难,特别是在薪酬待遇这方面,更是低得让人心寒。那么,如果能有一份在家就可以做的事情,而且是收入也不少,那将是很多普通人的最佳选择。在这里&#…...
创建SaaS产品帮助中心的关键步骤
帮助中心是一款SaaS产品必不可少的一部分,为了帮助用户更好的解决产品相关问题,提高新用户的使用体验,并且引导用户更好的使用产品,那么应该怎样制作帮助中心呢,每个产品帮助中心都需要有自己的风格,根据产…...
高频算法:Leetcode53 最大子数组和
今天讲的是Leetcode第53题,最大子数组和 首先观察题目,题目需要我们找出具有最大和的连续子数组,直接拿题目中的示例来做一个演示,找一找什么规律下的连续子数组才能得到最大的和 先从-2开始,-2 1 -1 此时我们的和…...
如何编写接口自动化测试框架、
编写接口自动化测试框架需要注意以下几点: 接口选择:首先确定需要测试的接口,包括请求方式、URL、参数、返回值等信息。 框架设计:设计一个灵活的框架,可以根据接口类型(RESTful API、SOAP API等ÿ…...
【Java面试八股文宝典之RabbitMQ篇】备战2023 查缺补漏 你越早准备 越早成功!!!——Day17
大家好,我是陶然同学,软件工程大三即将实习。认识我的朋友们知道,我是科班出身,学的还行,但是对面试掌握不够,所以我将用这100多天更新Java面试题🙃🙃。 不敢苟同,相信大…...
ESP32开发(1)----Espressif-IDE开发环境配置
Espressif-IDE开发环境配置前言一、ESP32-WROOM-32介绍二、IDE环境搭建三、建立第一个项目总结前言 最近得到一块ESP32-WROOM-32的开发板,没有原理图,但板子走线比较简单,看着板子上的布线大致猜一猜连接,然后试玩了一下…...
MyBatisPlus标准数据层开发
MyBatisPlus标准数据层开发2,标准数据层开发2.1 标准CRUD使用2.2 新增2.3 删除2.4 修改2.5 根据ID查询2.6 查询所有2.7 Lombok概念使用步骤步骤1:添加lombok依赖步骤2:安装Lombok的插件步骤3:模型类上添加注解2.8 分页功能步骤1:调用方法传入参数获取返回值步骤2:设…...
C/C++每日一练(20230412)
目录 1. 二维数组找最值 🌟🌟 2. 排序 🌟 3. 二叉树展开为链表 🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 二维…...
Leetcode.1379 找出克隆二叉树中的相同节点
题目链接 Leetcode.1379 找出克隆二叉树中的相同节点 easy 题目描述 给你两棵二叉树,原始树 original和克隆树 cloned,以及一个位于原始树 original中的目标节点 target。 其中,克隆树 cloned是原始树 original的一个 副本 。 请找出在树 …...
2022年团体程序设计天梯赛-总决赛
目录 一、L1-1 今天我要赢 二、L1-2 种钻石 三、L1-3 谁能进图书馆 四、L1-4 拯救外星人 五、L1-5 试试手气 六、L1-6 斯德哥尔摩火车上的题 七、L1-7 机工士姆斯塔迪奥 八、L1-8 静静的推荐 九、L2-1 插松枝 十、L2-2 老板的作息表 十一、L2-3 龙龙送外卖 十二、L…...
大数据技术之Sqoop——SQL to Hadoop
一、简介sqoop (sql to hadoop)是一款开源的工具,主要用于在 Hadoop(Hive)与传统的数据库(mysql、postgresql...)间进行数据的传递,可以将一个关系型数据库(例如 : MSQL,Oracle,Post…...
Java议题
序号议题 解释MyBatis官网1mapper文件中什么时候使用 # 什么时候必须用 $ 1、关键字作为参数,使用"$",两边不加""。 2、非关键字作为参数,使用"#"防注入。 其他情况优先使用"#" 2主键回填࿰…...
【阅读论文】USAD:多变量时间序列上的无监督异常检测
USAD : UnSupervised Anomaly Detection on Multivariate Time Series 摘要 IT系统的自动监控是Orange目前面临的挑战。考虑到其IT运营所达到的规模和复杂性,随着时间的推移,用于推断正常和异常行为的测量所需的传感器数量急剧增加,使得传统…...
Java多线程:ReentrantLock中的方法
公平锁与非公平锁 ReentrantLock有一个很大的特点,就是可以指定锁是公平锁还是非公平锁,公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的,而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,先来的未必就一…...
RabbitMQ初识快速入门
RabbitMQ初识&快速入门1.初识MQ1.1.同步和异步通讯1.1.1.同步通讯1.1.2.异步通讯1.2.技术对比:2.快速入门2.1.安装RabbitMQ2.1.1 下载镜像2.1.2 安装MQ2.2.RabbitMQ消息模型2.3.导入Demo工程2.4.入门案例2.4.1.publisher实现2.4.2.consumer实现2.5.总结1.初识MQ…...
由浅入深了解HashMap源码
由经典面试题引入,讲解一下HashMap的底层数据结构?这个面试题你当然可以只答,HashMap底层的数据结构是由(数组链表红黑树)实现的,但是显然面试官不太满意这个答案,毕竟这里有一个坑需要你去填&a…...
P5318 【深基18.例3】查找文献
题目描述 小K 喜欢翻看洛谷博客获取知识。每篇文章可能会有若干个(也有可能没有)参考文献的链接指向别的博客文章。小K 求知欲旺盛,如果他看了某篇文章,那么他一定会去看这篇文章的参考文献(如果他之前已经看过这篇参考…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...
跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践
在电商行业蓬勃发展的当下,多平台运营已成为众多商家的必然选择。然而,不同电商平台在商品数据接口方面存在差异,导致商家在跨平台运营时面临诸多挑战,如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...
AWS vs 阿里云:功能、服务与性能对比指南
在云计算领域,Amazon Web Services (AWS) 和阿里云 (Alibaba Cloud) 是全球领先的提供商,各自在功能范围、服务生态系统、性能表现和适用场景上具有独特优势。基于提供的引用[1]-[5],我将从功能、服务和性能三个方面进行结构化对比分析&#…...
