Springboot自动装配源码分析
版本
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version><relativePath/> <!-- lookup parent from repository --> </parent>
我们进入SpringBootApplication注解看看有什么
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
我们可以发现有一个@EnableAutoConfiguration注解,这个是实现自动装配的,继续进去看看
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
***
}
我们又看到了一个@Import({AutoConfigurationImportSelector.class})
他代表引入了AutoConfigurationImportSelector.class这个类,核心类,我们看看他的内容
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}
可以看到他继承了DeferredImportSelector类,这个类继承了ImportSelector 类。
然后前面说这个类是@Import引入的
@Import有三种使用的方法,其中一种,如果引入的类实现了ImportSelector接口,那么不会把引入的类加入容器,而是实现ImportSelector接口下的一个方法selectImports。
- 导入普通类
- 导入实现了ImportSelector接口的类
- 导入实现了ImportBeanDefinitionRegistrar接口的类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
****
}
public interface DeferredImportSelector extends ImportSelector {
***
}
这一句就是获取自动装配类的核心代码,我们进入到getAutoConfigurationEntry这个方法中去看,它是怎么获取配置的。
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}}
这个方法中this.getCandidateConfigurations(annotationMetadata, attributes)就是获取候选的配置类,接下来,我们就进入到getCandidateConfigurations这个方法中去查看SpringBoot是怎么获取这些候选的配置类。
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {AnnotationAttributes attributes = this.getAttributes(annotationMetadata);List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);configurations = this.removeDuplicates(configurations);Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = this.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}}
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());又是这个熟悉的方法SpringFactoriesLoader.loadFactoryNames()
这个方法在springboot启动流程中用到很多次,他就是去meta-inf下加载spring.factories文件。
利用SPI机制去加载配置类
SPI流程:
- 有关组织和公式定义接口标准
- 第三方提供具体实现: 实现具体方法, 配置 META-INF/services/${interface_name} 文件
- 开发者使用
SPI与API区别:
- API是调用并用于实现目标的类、接口、方法等的描述;
- SPI是扩展和实现以实现目标的类、接口、方法等的描述;
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");return configurations;}
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
跟我们上面说的一致。
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);if (result != null) {return result;} else {try {Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");LinkedMultiValueMap result = new LinkedMultiValueMap();while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);Iterator var6 = properties.entrySet().iterator();while(var6.hasNext()) {Entry<?, ?> entry = (Entry)var6.next();String factoryTypeName = ((String)entry.getKey()).trim();String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());int var10 = var9.length;for(int var11 = 0; var11 < var10; ++var11) {String factoryImplementationName = var9[var11];result.add(factoryTypeName, factoryImplementationName.trim());}}}cache.put(classLoader, result);return result;} catch (IOException var13) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);}}}
参考
深入理解 Java 中 SPI 机制 - 知乎
SpringBoot自动装配原理源码分析(详细)_springboot自动装配源码解析-CSDN博客
相关文章:

Springboot自动装配源码分析
版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version><relativePath/> <!-- lookup parent from repository --> </par…...
Visual Transformer (ViT)模型详解 动图讲解
1 Vit简介 1.1 Vit的由来 ViT是2020年Google团队提出的将Transformer应用在图像分类的模型,虽然不是第一篇将transformer应用在视觉任务的论文,但是因为其模型“简单”且效果好,可扩展性强(scalable,模型越大效果越好),成为了transformer在CV领域应用的里程碑著作,也…...
C++:完美转发(一)(std::forward)
一、理解引用折叠 (一)引用折叠 1. 在C中,“引用的引用”是非法的。像 auto& &rx x;(注意两个&之间有空格)这种直接定义引用的引用是不合法的,但是编译器在通过类型别名或模板参数推导等语境…...

西部首个全域直播基地,打造西部直播基地领军形象
天府锋巢直播产业基地作为西部直播产业的领军者,以其前瞻性的战略布局和卓越的服务体系,正加速推动全域直播的快速发展,助力直播产业实现新升级。该基地作为成都规模最大的直播基地,以加快全域直播为核心目标,通过促进…...

钟表——蓝桥杯十三届2022国赛大学B组真题
问题分析 这个问题的关键有两点:1.怎么计算时针,分针,秒针之间的夹角,2.时针,分针,秒针都是匀速运动的,并非跳跃性的。问题1很好解决看下面的代码就能明白,我们先考虑问题2…...

CSS 之 圆形波浪进度条效果
一、简介 本篇博客讲述了如何实现一个圆形波浪进度条的样式效果,具体效果参考下方GIF图。该样式的加载进度条可以用在页面跳转或数据处理等情况下的加载动画,比起普通的横条进度条来说,样式效果更生动美观。 实现思路: 这…...
按下鼠标进行拖拽,让元素跟随鼠标进行移动,鼠标抬起,元素停止移;js鼠标拖拽 (鼠标按下事件:onmousedown、鼠标移动事件:onmousemove、鼠标抬起事件:onmouseup)
需求如下: 按下鼠标进行拖拽,让元素跟随鼠标进行移动,鼠标抬起,元素停止移动。 解析: 鼠标按下事件:onmousedown 鼠标移动事件:onmousemove 鼠标抬起事件:onmouseup <!DOCT…...

第十二章 项目采购管理
12.1 规划采购管理 12.2 实施采购 12.3 控制采购 项目经理通常没有签订合同的权限,但必须熟悉正规的采购流程; 协议是采购的核心文件,关于协议我们要知道: 协议包括:合同、服务水平协议、谅解、协议备忘录或采购订单 ❗…...

PSFR-GAN复现
写在前面:本博客仅作记录学习之用,部分图片来自网络,如需引用请注明出处,同时如有侵犯您的权益,请联系删除! 文章目录 前言快速开始安装依赖权重下载及复原 训练网络数据集训练脚本 代码详解训练BaseOptio…...
函数和数组
一、函数 1.函数使用方法 定义函数再引用函数 2.基本函数格式 基本格式1: function 函数名{ 命令序列 } 基本格式2: 函数名(){ 命令序列 } 基本格式3: function func_name () {…...

docker安装时报错:Error: Nothing to do
安装docker时报以下错误 解决方法: 1.下载关于docker的相关依赖环境 yum -y install yum-utils device-mapper-persistent-data lvm22.设置下载Docker的镜像源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo3…...

白盒测试:覆盖测试及测试用例设计
白盒测试:覆盖测试及测试用例设计 一、实验目的 1、掌握白盒测试的概念。 2、掌握逻辑覆盖法。 二、实验任务 某工资计算程序功能如下:若雇员月工作小时超过40小时,则超过部分按原小时工资的1.5倍的加班工资来计算。若雇员月工作小时超过…...
Java高级开发2024高频面试提问题目
1、请先简单自我介绍一下自己?(一般不超过5min) 2、你最熟悉的项目是哪一个,讲一下用了哪些技术栈?(尽量讲出系统架构图使用到的技术组件和为什么选型这个组件?) 3、你项目中使用什…...
Kamailio openssl 3.0.x 需要注意的事项
我们留意到 Debian Bookworm 安装的 openssl 版本是 3.0.x 这里有几个地方要注意: modparam("tls", "init_mode", 1)核心参数 tls_threads_mode 配置为 1 或者 配置为 2,默认为 0版本建议用 5.8.1,貌似 5.7.x 也行 参…...

SpringAMQP Work Queue 工作队列
消息模型: 代码模拟: 相较于之前的基础队列,该队列新增了消费者 不再是一个,所以我们通过代码模拟出两个consumer消费者。在原来的消费者类里写两个方法 其中消费者1效率高 消费者2效率低 RabbitListener(queues "simple.queue")public voi…...

一分钟带你了解什么是等保测评
等保测评,即网络安全等级保护测评,是依据国家信息安全等级保护制度规定,对信息系统进行安全技术测评和安全管理测评,以确定系统的安全保护水平是否达到预定的安全等级要求。以下是等保测评的相关知识点总结: 测评概述&…...

宝塔面板怎么解决nginx跨域问题
1.找到宝塔的nginx配置文件 宝塔有一点不同,nginx配置文件不在nginx的安装目录中,应当去/www/server/panel/vhost/nginx找到 2.添加你要跨域的地址 location /api {proxy_pass http://localhost:8080;proxy_set_header Host $host;proxy_set_header X-…...
Python 自动化脚本系列:第1集
昨天写了一篇介绍如何使用Python实现自动化任务的,文章末尾介绍了一个简单的自动化脚本,因此今天编号从2开始。顺便附上昨天的文章链接: Python 自动化脚本系列:介绍 欢迎关注博主,持续输出更多Python相关内容&#…...

基于PHP开发的图片高清无损在线压缩源码系统 带完整源代码以及搭建教程
系统概述 高清无损在线压缩源码系统基于PHP语言开发,结合GD库和ImageMagick等图像处理工具,实现了对JPEG、PNG、GIF等多种图片格式的高清无损压缩。系统采用B/S架构,用户只需通过浏览器访问系统界面,即可实现图片的上传、压缩、预…...

Linux提权--SUDO(CVE-2021-3156)Polkit(CVE-2021-4034)
免责声明:本文仅做技术学习与交流... 目录 SUDO(CVE-2021-3156) 影响版本 -判断: -利用: Polkit(CVE-2021-4034) -判断: -利用: 添加用户 SUDO(CVE-2021-3156) another: SUDO权限配置不当. 影响版本 由系统的内核和发…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...