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知识库已经正式入驻钉钉应用市场…

Flutter 中的 SlideTransition 小部件:全面指南

Flutter 中的 SlideTransition 小部件&#xff1a;全面指南 在 Flutter 中&#xff0c;SlideTransition 是一个动画组件&#xff0c;用于创建滑动动画效果&#xff0c;使得子组件可以沿着一个轴滑动进入或滑动退出视图。这种动画效果常用于页面转场、菜单展开收起、元素的添加…

2024-5-8——给植物浇水

2024-5-8 题目来源我的题解方法一 模拟 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2079 我的题解 方法一 模拟 依次模拟浇水动作 使用一个变量 cap维护剩余的水量&#xff0c;使用t作为还未浇水的树的下标。当从第 i−1株植物到达第 i株植物时&#xff1a; 如果 ca…

前端中css穿透样式:deep的用法

在前端开发中&#xff0c;尤其是使用 Vue.js 这样的框架时&#xff0c;有时我们需要在子组件中修改或影响由父组件传递下来的样式。然而&#xff0c;由于组件的封装和样式隔离&#xff0c;直接修改子组件中的样式可能不起作用。这时&#xff0c;我们可以使用 ::v-deep 伪元素来…

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

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

【4th chapter】信息安全技术—安全技术、安全架构、安全策略、安全管理、软件的脆弱性

概要 安全技术安全架构安全策略安全管理软件的脆弱性加密技术&#xff08;Encryption Technology&#xff09;安全域架构&#xff08;Security Domain Architecture&#xff09;访问控制策略&#xff08;Access Control Policy&#xff09;信息安全管理体系&#xff08;Inform…

面试数据库八股文十问十答第六期

面试数据库八股文十问十答第六期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;来说说一条 SQL 语句的执行…

leetcode题目238

除自身以外的数组的乘积 中等 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&…

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

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

进程与线程学习

多线程 tthreading.Thread(targettask,arge(11,)) start&#xff08;&#xff09;开始 join&#xff08;&#xff09;等待 主线程在默认情况下会等待所有非守护线程&#xff08;子线程&#xff09;结束后才会结束程序。也就是说&#xff0c;如果主线程在结束前没有调用所有…

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 添加可执…

【八股系列】谈谈关于对webpack热更新的原理?

文章目录 1. 热更新原理2. 热更新配置 1. 热更新原理 Webpack 的热模块替换&#xff08;Hot Module Replacement&#xff0c;HMR&#xff09;是一种在不完全刷新页面的情况下更新应用代码的技术&#xff0c;从而提高了开发效率。以下是 HMR 的核心原理&#xff1a; 步骤描述1…

tcpdump抓包,抓包导出.pcap文件用wireshark看

1、抓所有口的包 tcpdump -i any host 设备的ip2、抓特定口的包 tcpdump -i eth2 port 61182 -nne3、将抓到的包导出到pacb文件 tcpdump -i eth2 port 61182 -nne -s0 -w /tmp/61182.pcap -s0: Sets the snapshot length to capture the entire packet. The 0 means that tcpd…

《征服数据结构》目录

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