【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 求知欲旺盛,如果他看了某篇文章,那么他一定会去看这篇文章的参考文献(如果他之前已经看过这篇参考…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
