SpringBoot自动装配源码

自动装配:

实际上就是如何将Bean自动化装载到IOC容器中管理,Springboot 的自动装配时通过SPI 的方式来实现的

SPI:SpringBoot 定义的一套接口规范,这套规范规定:Springboot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 Springboot 定义的标准,就能将自己的功能装置进 Springboot。

Springboot 通过@EnableAutoConfiguration开启自动装配,我们点进去发现一个@Import(AutoConfigurationImportSelector.class) 查看他的Diagrams发现它继承于ImportSelector 在Spring源码中见到过,那我们就找selectImports() 方法

在这里插入图片描述

AutoConfigurationImportSelector → selectImports()

这里就是自动装配的核心代码了getAutoConfigurationEntry

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {AnnotationAttributes attributes = this.getAttributes(annotationMetadata);// 通过 SpringFactoriesLoader.loadSpringFactories() // 加载META-INF/spring.factories中的配置List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);// 去除重复项configurations = this.removeDuplicates(configurations);// 应用exclusion属性,排除掉的引入// 开发过程中某些服务不需要的配置信息可以在注解后加上(exclude = xxxAutoConfiguration.class)来排除加载Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);// 检查候选配置类上的注解@ConditionalOnClass// 如果要求的类不存在,则这个候选类会被过滤不被加载configurations = this.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}
}

通过this.getCandidateConfigurations()发现是SpringFactoriesLoader.loadSpringFactories() 加载META-INF/spring.factories中的配置来实现的

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {Map<String, List<String>> result = (Map)cache.get(classLoader);if (result != null) {return result;} else {Map<String, List<String>> result = new HashMap();try {Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories");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()) {Map.Entry<?, ?> entry = (Map.Entry)var6.next();String factoryTypeName = ((String)entry.getKey()).trim();String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());String[] var10 = factoryImplementationNames;int var11 = factoryImplementationNames.length;for(int var12 = 0; var12 < var11; ++var12) {String factoryImplementationName = var10[var12];((List)result.computeIfAbsent(factoryTypeName, (key) -> {return new ArrayList();})).add(factoryImplementationName.trim());}}}result.replaceAll((factoryType, implementations) -> {return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));});cache.put(classLoader, result);return result;} catch (IOException var14) {throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);}}
}

this.getConfigurationClassFilter().filter(configurations) 这里是如何过滤的我们继续深入看一下在内部类ConfigurationClassFilter的实现

在这里插入图片描述

ConfigurationClassFilter.java中autoConfigurationMetadata 属性在构造函数中进行了赋值,查看loadMetadata() 发现是根据PATH = "META-INF/spring-autoconfigure-metadata.properties" 文件中的信息进行判断的

protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";private AutoConfigurationMetadataLoader() {}static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {return loadMetadata(classLoader, PATH);}static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {try {Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path): ClassLoader.getSystemResources(path);Properties properties = new Properties();while (urls.hasMoreElements()) {properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));}return loadMetadata(properties);}catch (IOException ex) {throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);}}

我们拿出META-INF/spring-autoconfigure-metadata.properties 中一部分数据

org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$MessagingTemplateConfiguration=
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration$MessagingTemplateConfiguration.ConditionalOnClass=org.springframework.amqp.rabbit.core.RabbitMessagingTemplate

分析发现如果项目中不存在org.springframework.amqp.rabbit.core.RabbitMessagingTemplate 这个类,那么在容器启动时就不加载。也就是说我们用的时候直接引入这个starter,启动的时候就会加载这个starter里的配置,不引入就不加载。META-INF/spring.factories 里的自动加载信息是为了方便我们后期引入不需要额外再进行配置。

总结:

Srpingboot使用@EnableAutoConfiguration 注解开启自动装配,通过SpringFactoriesLoader.*loadFactoryNames()*加载META-INF/spring.factories中的自动配置类实现自动装配,通过@ConditionalOn...按需加载的配置类过滤掉未引入用不到的项

@ConditionalOn 条件注解:

@ConditionalOnBean:当容器里有指定 Bean 的条件下

@ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下

@ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean

@ConditionalOnClass:当类路径下有指定类的条件下

@ConditionalOnMissingClass:当类路径下没有指定类的条件下

@ConditionalOnProperty:指定的属性是否有指定的值

@ConditionalOnResource:类路径是否有指定的值

@ConditionalOnExpression:基于 SpEL 表达式作为判断条件

@ConditionalOnJava:基于 Java 版本作为判断条件

@ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置

@ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下

@ConditionalOnWebApplication:当前项目是 Web 项 目的条件下

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

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

相关文章

css 渐变色边框

效果图&#xff1a; 代码&#xff1a; <style>:root{--br-radius: 12px;}.list{position: relative;}.list_tle{margin-top: 15px;margin-bottom: 5px;}.item{position: relative;display: inline-flex;} .br1 {padding: 10px 16px;clip-path: inset(0 round 6px);borde…

官宣|HelpLook现已入驻钉钉应用市场,助力企业知识管理知识

前一阵子OpenAI公司最新的GPT-4o技术震撼发布&#xff0c;人工智能的实际应用前景再次引起行业瞩目&#xff0c;或者被GPT4o的数据分析等特色功能折服。如您正寻求将AI技术融入企业知识管理&#xff0c;不要错过HelpLook&#xff01;HelpLook AI知识库已经正式入驻钉钉应用市场…

基于Android的家庭理财APP的设计与实现(论文+源码)_kaic

摘 要 随着我国居民收入和生活水平的提高&#xff0c;家庭理财成为人们热议的焦点问题。在需求分析阶段&#xff0c;系统从用户的实际需求出发&#xff0c;确定了用户账户管理、记账、数据分析和提醒功能等几个核心需求。用户账户管理包括用户注册、登录和密码找回等基本操作…

大数据技术Hbase列数据库——topic1

目录 搭建单机版Hbase验证方法一验证方法二 搭建单机版Hbase 验证方法一 使用 jps 命令查看 HMaster 进程是否启动 首先使用xftp 7上传hbase-2.1.0安装压缩包到虚拟机进行解压缩到某一地址&#xff0c;这里解压缩到了上传的路径即/root/software/ tar -zxvf hbase-2.1.0-bi…

2025第十届美陈展

展位又遭疯抢&#xff01;2025第十届美陈展释放“无界之美” 美是全球通用的语言&#xff0c;人类对美的追求始终如一&#xff0c;大众审美在经历了时代的变迁后开始趋同&#xff0c;东方文明深处的美学经济开始崛起。 在如今商业迈入存量阶段&#xff0c;以品牌为突破口打造…

基于 vuestic-ui 实战教程 - 登录篇

1. 简介 登录做为一个系统的门面&#xff0c;也是阻挡外界的一道防线&#xff0c;那在vuestic-ui中如何做登录功能呢。在这里就之间沿用初始版本的Login页面&#xff0c;作为一个演示模板&#xff0c;后续需要改进的读者可以在此篇文章的基础上修改。 2. 登录接口相关api 与 t…

python连接mysql,并整理(去哪儿网)页面数据到表

##引入requests/pymysql模块 本地安装mysql数据库&#xff0c;安装图形化工具navicat import requests from pymysql import Connect#创建客户端连接信息 client Connect(host127.0.0.1,port3306,userroot,password, ) #创建游标 cursor client.cursor() cursor.execute(cre…

17- PHP 开发-个人博客项目TP 框架路由访问安全写法历史漏 洞

常见的php框架&#xff1a;laravel和thinkphp和yii 这里以thinkphp为例 thinkphp目录访问设置 这里只找到了这个3.多的源代码&#xff0c;没找点5.的&#xff0c;凑合一下 链接&#xff1a;GitHub - top-think/thinkphp: ThinkPHP3.2 ——基于PHP5的简单快速的面向对象的PHP…

HTML用法介绍

文章目录 一、HTML概念和模版二、常用标签及用法1.p标签2.span标签3.h标签4.hr标签5.img标签6.a标签7.input标签8.table标签 一、HTML概念和模版 HTML的全称为超文本标记语言&#xff0c;它包括一系列标签组成&#xff0c;模版及各部分注释如下&#xff1a; <!--声明文档类…

ROS基础学习-话题通信机制研究

研究ROS通信机制 研究ROS通信机制 0.前言1.话题通信1.1 理论模型1.2 话题通讯的基本操作1.2.1 C++1.2.2 Python中使用自己的虚拟环境包1.2.2.1 参考11.2.2.2 参考21.2.2.3 /usr/bin/env:“python”:没有那个文件或目录1.2.3 Python1.2.2.1 发布方1.2.2.2 订阅方1.2.2.3 添加可执…

《征服数据结构》目录

我们知道要想学好算法&#xff0c;必须熟练掌握数据结构&#xff0c;数据结构常见的有 8 大类&#xff0c;分别是数组&#xff0c;链表&#xff0c;队列&#xff0c;栈&#xff0c;散列表&#xff0c;树&#xff0c;堆&#xff0c;图。但如果细分的话就比较多了&#xff0c;比如…

go-zero 实战(2)

go-zero 实战&#xff08;1&#xff09; 中&#xff0c;使用了go-zero 创建了order 和 user 两个微服务。而order作为grpc的客户端&#xff0c;user 作为grpc的服务端&#xff0c;打通了 order 到 user的调用。接下来&#xff0c;我们在user中&#xff0c;加入mysql组件。确保数…

我说同事咋找工作命中率这么高,原来是学习了这些招式

最近有两个同事离职了&#xff0c;其中一个还是专科&#xff0c;他俩一个是前端开发&#xff0c;一个是python开发&#xff0c;两个人都接近35岁了。我们还劝告他们&#xff0c;不要离职&#xff0c;要骑驴找马。但了解后&#xff0c;他俩非常有信心的说&#xff1a;不怕&#…

3D视觉技术|螺栓分拣测试

随着制造业自动化程度的不断提高&#xff0c;某大型汽配企业为提升生产效率、减少人力成本&#xff0c;提出了使用复合机器人完成螺栓分拣的需求。富唯智能通过采用复合机器人&#xff0c;结合3D工业相机和高性能控制器&#xff0c;实现螺栓的自动抓取&#xff0c;从而提升生产…

鸿蒙OS开发:【一次开发,多端部署】(一多天气)项目

一多天气 介绍 本示例展示一个天气应用界面&#xff0c;包括首页、城市管理、添加城市、更新时间弹窗&#xff0c;体现一次开发&#xff0c;多端部署的能力。 1.本示例参考一次开发&#xff0c;多端部署的指导&#xff0c;主要使用响应式布局的栅格断点系统实现在不同尺寸窗…

【Qt 学习笔记】Qt窗口 | 工具栏 | QToolBar的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt窗口 | 工具栏 | QToolBar的使用及说明 文章编号&#xff1a;Qt 学习…

opencv文档py_contours示例整理

文章目录 目录说明contours_begin目标什么是轮廓?如何画等高线?轮廓逼近法contour_features目标1.Moments 时刻2. Contour Area 轮廓面积3. Contour Perimeter 轮廓周长4. Contour Approximation 轮廓近似5. Convex Hull 凸包6. Checking Convexity 检查凸性7. Bounding Rect…

嵌入式进阶——RTC时钟

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 RTC时钟原理图PCF8563寄存器控制与状态寄存器 设备地址I2C环境初始化RTC寄存器数据读取RTC寄存器数据写入RTC闹钟设置RTC定时器设置…

2024.5.28晚训题解

提前预告&#xff0c;市赛初中组会考算法题&#xff0c;应该会有两道模板题 比如DFS BFS 二分 简单动态规划&#xff0c;虽然我们没学多久&#xff0c;但是模板题你还是要会写的 A题 编辑距离 动态规划 注意多组输入 #include<iostream> using namespace std; int dp[1…

9、C#【进阶】特性

特性 文章目录 1、特性概念2、自定义特性 Attribute3、特性的使用4、限制自定义特性的使用范围5、系统自带特性1、过时特性2、调用者信息特性3、条件编译特性4、外部dll包函数特性 1、特性概念 特性是一种允许我们向程序的程序集添加元数据的语言结构 它是用于保存程序机构信息…