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 项 目的条件下

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

栈(从数据结构的三要素出发)

文章目录 逻辑结构物理结构顺序栈链栈共享栈 数据的操作顺序栈的基本操作链栈的基本操作共享栈的基本操作 数据结构的应用栈在括号匹配中的应用栈在表达式求值中的应用栈在递归调用中的应用 逻辑结构 栈是只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表&#xf…

保留两位小数不四舍五入,10000.55变成10000.54的坑

正解 function moneyFormat(num){ let money num "";//隐式转换为字符串和toString()效果一样//没有小数补齐这个0if(money.indexOf(".")"-1"){moneymoney".00";}else{//有小数截取前二位小数moneymoney.substring(0,money.inde…

工业AI的崛起,中国自主创新的新机遇

我们都知道&#xff0c;互联网已经深刻地改变了我们的生活方式&#xff0c;催生了无数的新型商业模式和创新产业&#xff0c;推动了社会的经济变革。中国在互联网领域的发展取得了举世瞩目的成就&#xff0c;建成了全球规模最大、技术领先的5G网络&#xff0c;互联网应用的普及…

vue3 vite title 页面标题设置

效果图&#xff1a; 1. 安装 vite-plugin-html 插件 npm install vite-plugin-html -D2. 修改 vite.config.js import {defineConfig, loadEnv} from vite import { createHtmlPlugin } from "vite-plugin-html" import {resolve} from path import vue from vitej…

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

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

振弦采集仪在岩土工程地质灾害监测中的可行性研究

振弦采集仪在岩土工程地质灾害监测中的可行性研究 引言&#xff1a; 岩土工程地质灾害是指在岩土体中由于自然力和人类活动等因素引起的&#xff0c;对人类生活、财产以及环境造成威胁的灾害。为了及时发现并准确监测地质灾害的发生和演化过程&#xff0c;振弦采集仪作为一种新…

web自动化-下拉框操作/键鼠操作/文件上传

在我们做UI自动化测试的时候&#xff0c;会有一些元素需要特殊操作&#xff0c;比如下拉框操作/键鼠操作/文件上传。 下拉框操作 在我们很多页面里有下拉框的选择&#xff0c;这种元素怎么定位呢&#xff1f;下拉框分为两种类型&#xff1a;我们分别针对这两种元素进行定位和…

6-4 先序输出度为2的结点

作者 DS课程组 单位 临沂大学 本题要求实现一个函数&#xff0c;按照先序遍历的顺序输出给定二叉树中度为2的结点。 函数接口定义&#xff1a; void PreorderPrintNodes( BiTree T);T是二叉树树根指针&#xff0c;PreorderPrintNodes按照先序遍历的顺序输出给定二叉树T中度为…

随笔(二)——项目代码优化

文章目录 前言一、传入的props的默认值定义为空数组1.问题&#xff08;提示对象的类型为unknwn&#xff09;2.优化 二、document 上不存在xxx属性1.问题2.做了一个兼容浏览器的关闭全屏方法3. 解决方法 &#xff08;使用declare globa设置全局变量类型&#xff09;&#xff08;…

ssm球场计费管理系统-计算机毕业设计源码77275

摘 要 大数据时代下&#xff0c;数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求&#xff0c;利用互联网服务于其他行业&#xff0c;促进生产&#xff0c;已经是成为一种势不可挡的趋势。在球馆计费管理的要求下&#xff0c;开发一款整体式结构的球场计费管理…

配置阿里yum源

配置阿里yum源&#xff08;这个很重要&#xff09;&#xff1a;https://developer.aliyun.com/article/1480470 1.备份系统自带yum源配置文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup2.下载ailiyun的yum源配置文件 2.1 CentOS7 wge…

专业软件测试机构CMA、CNAS资质与测试报告介绍

软件测试机构 一、专业软件测试机构CMA和CNAS的资质介绍如下&#xff1a; 1.CMA&#xff08;China Inspection Body and Laboratory Mandatory Approval&#xff09;是中国计量认证的缩写&#xff0c;是由中国计量认证机构对软件测试实验室在测试技术能力、测试设备、质量保证…

【Java面试】四、MySQL篇(上)

文章目录 1、定位慢查询2、慢查询的原因分析3、索引3.1 数据结构选用&#xff1a;二叉树 & 红黑树3.2 数据结构选用&#xff1a;B树 4、聚簇索引、非聚簇索引、回表查询4.1 聚簇索引、非聚簇索引4.2 回表查询 5、覆盖索引、超大分页优化5.1 覆盖索引5.2 超大分页处理 6、索…

Stable Diffusion AI绘画:从提示词到模型出图的全景指南

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

Python Anaconda环境复制

虚拟环境复制 conda-pack 第一种方式 conda打包 在打包之前如果没有conda-pack包的话&#xff0c;需要安装pip install conda-pack打包 conda pack -n py36 -o py366.tar.gz -o就是给导出得到的压缩包就在当前目录下 传输到另外一台服务器上 有两台linux服务器&#xff0c…

30V MOS管 60VMOS管 100VMOS管 150VMOS管推荐

MOS管&#xff0c;即金属氧化物半导体场效应管&#xff0c;其工作原理是&#xff1a;在P型半导体与N型半导体之间形成PN结&#xff0c;当加在MOS管栅极上的电压改变时&#xff0c;PN结之间的沟道内载流子的数量会随之改变&#xff0c;沟道电阻也会发生改变&#xff0c;进而改变…

Docker部署后的中文乱码问题

本地和服务器上面生成图片文字多没有乱码&#xff0c;但是服务部署到docker上面就开始出现乱码。排查了一下发现是docker上缺少相应的中文字体&#xff0c;添加字体即可解决。 1.在网站上找到相关资源并下载字体-字体下载-字体下载大全-字体免费下载|字体下载 2.上传到服务器 …

无忧企业文档专为企业打造智能文档管理

在当今这个信息化快速发展的时代&#xff0c;企业运营中产生的文档数量日益增多&#xff0c;如何高效、安全地管理这些文档成为了企业发展过程中不可忽视的问题。那么&#xff0c;企业需要什么样的文档管理系统呢&#xff1f;无忧企业文档&#xff0c;作为一款专为现代企业打造…

使用Prometheus组件node_exporter采集linux系统的指标数据(包括cpu/内存/磁盘/网络)

一、背景 Linux系统的基本指标包括cpu、内存、磁盘、网络等&#xff0c;其中网络可以细分为带宽进出口流量、连接数和tcp监控等。 本文使用Prometheus组件node_exporter采集&#xff0c;存储在promethues&#xff0c;展示在grafana面板。 二、安装node_exporter 1、下载至本…

PID控制中积分项目的理解,消除稳态误差的作用,表示着过去(PID积分控制)

1&#xff0c;消除稳态误差 积分项目是对于历史误差进行的累积&#xff0c;可以理解&#xff0c;系统的误差累积表示不断的在减少误差&#xff0c;最终消除误差&#xff0c;这个过程需要将误差进行累加&#xff0c;才可以真正知道误差的大小是多少&#xff0c;用最终累加的误差…