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权限配置不当. 影响版本 由系统的内核和发…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...
9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
C++ 类基础:封装、继承、多态与多线程模板实现
前言 C 是一门强大的面向对象编程语言,而类(Class)作为其核心特性之一,是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性,包括封装、继承和多态,同时讨论类中的权限控制,并展示如何使用类…...
【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项
一、条形码识别改名使用教程 打开软件并选择处理模式:打开软件后,根据要处理的文件类型,选择 “图片识别模式” 或 “PDF 识别模式”。如果是处理包含条形码的 PDF 文件,就选择 “PDF 识别模式”;若是处理图片文件&…...
el-amap-bezier-curve运用及线弧度设置
文章目录 简介示例线弧度属性主要弧度相关属性其他相关样式属性完整示例链接简介 el-amap-bezier-curve 是 Vue-Amap 组件库中的一个组件,用于在 高德地图 上绘制贝塞尔曲线。 基本用法属性path定义曲线的路径,可以是多个弧线段的组合。stroke-weight线条的宽度。stroke…...
