[Spring Boot Starter系列]Spring Boot自动装配原理

news2024/12/23 17:35:58

目录

一、介绍

二、Spring Boot实现自动装配的简单流程(基于2.3.5.RELEASE版本)

三、总结


一、介绍

什么是Spring Boot的自动装配?

以下描述部分来自Spring Boot官网:

  • Spring Boot自动配置尝试根据您添加的jar依赖项自动配置您的Spring应用程序。
  • 您需要通过将@EnableAutoConfiguration或@SpringBootApplication注释添加到您的一个@Configuration类中来选择自动配置。您应该只添加一个@SpringBootApplication或@EnableAutoConfiguration注释。

补充:

  • 上诉说到Spring Boot会根据添加的jar依赖项自动配置您的Spring应用程序,具体的实现是通过扫描到引用的jar包中的META-INF/spring.factories文件,获取到你的配置类,文件内容大致如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.ricardo.cn.config.MyAutoConfigure

通过以上描述,个人理解为,自动装配就是能够为你创建你在jar包中定义的Bean,将其装配到容器中,供你使用你在jar包中实现的功能。

如果你想开发一个能够被Spring Boot自动装配所识别的Spring Boot Starter组件,那么请参考以下我的另外一篇博客,包含了开发的具体流程:

[自动装配系列]spring-boot-starter组件自定义开发及应用_明天再去学习的博客-CSDN博客

二、Spring Boot实现自动装配的简单流程(基于2.3.5.RELEASE版本)

1、通过上诉描述,Spring Boot想要实现自动装配,首先,你得需要在你的配置类中使用@SpringBootApplication或@EnableAutoConfiguration注解,毫无疑问,我们需要关注的只是@EnableAutoConfiguration注解,为什么这么说呢,请看@SpringBootApplication注解的内容:

@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 {}

可以看到,即使是@SpringBootApplication注解,其中也包含@EnableAutoConfiguration注解,所以@EnableAutoConfiguration注解是自动装配功能主入口。

2、@EnableAutoConfiguration注解内容如下:

@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 {};
}

官网中有这么一句话:

The @Import annotation can be used to import additional configuration classes

大致意思是说,@Import注解可以用于 导入其他配置类,所以,我们将关注点放在AutoConfigurationImportSelector.class上。

3、AutoConfigurationImportSelector.class的基础信息如下:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}



public interface DeferredImportSelector extends ImportSelector {}



public interface ImportSelector {
}

当我定位到这个类之后,很疑惑,该把断点定位在何处,百度之后,有说是selectImport方法,有说是process方法,那到底是哪一个呢?很简单,两个方法都打一下断点。

3、将断点打在AutoConfigurationImportSelector.class的selectImport方法上。

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

将断点打到此处后,启动debug模式,发现进不来,说明我这个版本的Spring Boot,selectImport方法不是主入口。

 

4、将断点打在AutoConfigurationImportSelector.class的process方法上。

public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
            Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
                return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
            });
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
            this.autoConfigurationEntries.add(autoConfigurationEntry);
            Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();

            while(var4.hasNext()) {
                String importClassName = (String)var4.next();
                this.entries.putIfAbsent(importClassName, annotationMetadata);
            }

        }

将断点打到此处后,启动debug模式,发现进来了,说明我这个版本的Spring Boot,process方法是主入口。

在该方法中一步步debug走下去,查看参数内容:

当执行完getAutoConfigurationEntry方法时,可以看到返回结果如上图所示,都是AutoConfiguration结尾的配置(WhiteListAutoConfiguratio是我自定义的Spring Boot Starter组件,看到他之后,更加确定是getAutoConfigurationEntry方法了)。

5、给getAutoConfigurationEntry方法打断点。

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);
        }
    }

在该方法中一步步debug走下去,查看参数内容:

 当执行完getCondidateConfigurations方法时,可以看到返回结果如上图所示,都是AutoConfiguration结尾的配置,可以确定自动装配与该方法有关。

6、查看getCondidateConfigurations方法。

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;
    }

通过该方法中英文描述可以看出,自动装配扫描的是META-INF/spring.factories文件。

7、通过上诉流程,进入到SpringFactoriesLoader.loadFactoryNames

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

进入到关键方法loadSpringFactories,一步步断点走下去,urls中包含了我们的所有外部jar包(通过debug查看到了urls内容),然后遍历每个jar包,扫描到我们jar包下的META-INF/spring.factories,获取到我们的配置类。

当调用完上诉步骤后,返回结果如下:

在步骤6中,又通过EnableAutoConfiguration.class从上诉集合中取到相关的value值列表。

8、至此,我们便拿到了需要自动装配的配置类,进行初始化。

三、总结

该文章主要是作为我以下的文章的支撑,只是作为学习参考,如果内容有错误的地方,可以进行留言提示,我看到的话会进行更正,谢谢:

[自动装配系列]spring-boot-starter组件自定义开发及应用_明天再去学习的博客-CSDN博客

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

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

相关文章

《kafka 核心技术与实战》课程学习笔记(八)

无消息丢失配置怎么实现&#xff1f; Kafka 只对“已提交”的消息&#xff08;committed message&#xff09;做有限度的持久化保证。 第一个核心要素是“已提交的消息”。 当 Kafka 的若干个 Broker 成功地接收到一条消息并写入到日志文件后&#xff0c;它们会告诉生产者程序…

机器学习4:基本术语

机器学习涉及很多专业术语&#xff0c;为了避免混淆概念&#xff0c;我们在学习中&#xff0c;首先必须统一语言&#xff1a;即充分理解专业术语&#xff0c;并采用专业术语来描述机器学习相关的内容。本节将介绍几种基本的机器学习术语。 目录 1.标签 2.特征 3.示例 4.模…

shardingjdbc入门-自问自答

1&#xff1a;shardingjdbc 是什么&#xff0c;它能做什么,解决了什么问题&#xff1f; 现实的问题是mysql单表存储是有上线的&#xff0c;因为mysql采用的是 B 树类型的索引&#xff0c;在数据量超过阈值的时候&#xff0c;索引的持续变大&#xff0c;会导致访问磁盘的IO次数增…

【永久服务器】EUserv

1. 请先自行准备网络&#xff08;我用的伦敦还可以&#xff09;、以及visa卡&#xff0c;淘宝可以代付&#xff0c;我总共花了97人民币&#xff08;10.94欧代付费&#xff09; 现在只能申请一台&#xff0c;多了会被删除&#xff0c;也就是两欧元&#xff0c;然后选择visa卡 选…

正版软件 | RadiAnt DICOM Viewer - 医学图像的PACS DICOM浏览器

辐射蚂蚁DICOM查看器 2023.1 最新版。 新增功能&#xff1a; 长度比计算。椭球体/子弹体积计算。添加了在 DICOM 标记窗口中将特定项目着色和/或固定到顶部的选项。 改进和错误修复&#xff1a; 使用多个关键字&#xff08;用 |&#xff09; 分隔&#xff09;搜索本地存档。…

0基础学习VR全景平台篇第49篇:高级功能-自定义LOGO

功能位置示意 一、本功能将用在哪里&#xff1f; 自定义logo功能&#xff0c;可以在全景作品中自定义植入商企logo&#xff0c;让全景自带推广属性&#xff0c;使宣传效果事半功倍。 备注&#xff1a;不同皮肤自定义logo显示位置不同。 点击这里 查看案例 二、如何使用本功能…

智云通CRM:引领企业数字化转型的利器

在如今的商业竞争中&#xff0c;客户管理是企业成功的关键因素之一。然而&#xff0c;传统的客户管理方式已经无法满足企业日益增长的需求&#xff0c;企业需要一个强大的工具来帮助他们更好地管理客户关系&#xff0c;并实现数字化转型。智云通CRM系统作为最佳解决方案&#x…

Spring Boot 如何防止重复请求?| 超级详细,建议收藏

1. 前言&#x1f525; 在日常业务开发中,处理重复请求应该是我们需要经常注意的&#xff0c;在某些情况下是可能重复发送的&#xff0c;如果是查询类操作并无大碍&#xff0c;但其中有些请求是涉及写入操作的&#xff0c;一旦重复了&#xff0c;很可能会导致很严重的后果&#…

【Python】模块导入 ② ( 模块导入语法 | 导入完整模块 | import 导入完整模块 | from 导入完整模块 )

文章目录 一、导入完整模块 - import 导入完整模块1、import 导入完整模块2、代码示例 - 导入 time 时间模块 二、导入完整模块 - from 导入完整模块1、from 导入完整模块2、代码示例 - from 导入完整模块 一、导入完整模块 - import 导入完整模块 1、import 导入完整模块 使用…

Mybatis背景简介及其优缺点

文章目录 1. JDBC简介1.1 jdbc架构图1.2 jdbc例子1.3 jdbc缺点 2. Mybatis2.1 iBATIS是什么2.2 Mybatis是什么2.3 和其他持久层框架的本质区别2.4 Mybatis和Hibernate的共同点2.5 Mybatis的优缺点2.5.1 Mybatis的优点2.5.2 Mybatis的缺点 2.6 Hibernate的优缺点2.6.1 Hibernate…

工作流引擎技术选型

一、主流开源框架介绍 1、工作流相关文档 1.Camunda 官方文档&#xff1a;https://camunda.com/ 中文文档&#xff1a;介绍 | docs.camunda.org 2.Activiti 官方文档&#xff1a;https://www.activiti.org/ 中文文档&#xff1a;[activiti6用户手册 3.Snaker 官方文档&…

【PCIE体系结构十四】电气物理层之发送端FFE

&#x1f449;个人主页&#xff1a;highman110 &#x1f449;作者简介&#xff1a;一名硬件工程师&#xff0c;持续学习&#xff0c;不断记录&#xff0c;保持思考&#xff0c;输出干货内容 参考书籍&#xff1a;《PCI.EXPRESS系统体系结构标准教材 Mindshare》 参考文章&…

Docker 安装 Nginx,并实现负载均衡

1、获取 nginx 的镜像 # 默认是latest版本docker pull nginx 2、运行 nginx 容器 docker run --name nginx-80 -p 80:80 --rm -d nginx# --name nginx-80 设定容器的名称# -p 80:80 端口进行映射&#xff0c;将本地的80端口映射到容器内部的80端口# --rm 表示容器退出后直接…

云安全技术——Hyper-V虚拟化技术

目录 5-1 了解Hyper-V 5-2 安装Hyper-V 5-3创建虚拟机 Hyper-V虚拟化技术 实验目的 了解 Windows 虚拟化的概念 了解 Hyper-V的背景及发展 了解 Hyper-V 的功能特性 了解 Hyper-V的体系架构 实验要求 能描述 Hyper-V 的功能特性 能在 Windows 2012 R2系统下部署 Hyper-V 能使…

SpringBoot整合MyBatis分页

SpringBoot整合MyBatis分页 一、pagehelper分页1、添加相关依赖2、添加相关配置3、添加分页配置4、添加代码5、测试 二、拦截器分页1、添加相关配置2、添加拦截器代码和配置3、添加代码4、测试4、测试 本文目标&#xff1a; SpringBoot整合Mybatis分页的两种方式&#xff0c;一…

Python基础八

目录 一、Python条件控制语句 1.执行过程 2.if 语句 if中常用的操作运算符: if 嵌套 3.match...case语句 二、Python循环控制语句 1.while循环 while无限循环 while 循环使用 else 语句 2.for 循环语句 for...in...循环 for循环使用else语句 for...in range()…

2023年3季度DAMA-CDGA/CDGP数据治理认证即将开班

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

你知道ai绘画生成器怎么弄吗

在数字时代&#xff0c;艺术也开始走向了自动化。随着人工智能技术的进步&#xff0c;ai绘画软件已经开始逐渐普及。它们可以利用先进的神经网络算法&#xff0c;学习人类艺术家的风格和技巧&#xff0c;从而生成出高度逼真的艺术作品。这些作品虽然没有人类艺术家的创意和灵魂…

Linux系统编程(终端和进程的关系)

文章目录 前言一、终端和控制台二、TTY和PTY三、终端的类型四、Gnome Terminal伪终端总结 前言 本篇文章带大家学习终端和进程的关系&#xff0c;终端相信大家都听过&#xff0c;那么真的理解终端是什么吗&#xff1f;应该有很多同学对于终端只是有一个模糊的概念。那么这篇文…

【算法题】合并两个有序链表、删除字符串 s1 中在字符串 s2 中出现的字符、求一个论坛一天的在线人数分布

合并两个有序链表、删除字符串 s1 中在字符串 s2 中出现的字符、求一个论坛一天的在线人数分布 一、合并两个有序链表1.1、题目描述1.2、思路1.3、代码实现1.4、小结 二、删除字符串 s1 中在字符串 s2 中出现的字符2.1、题目描述2.2、思路2.3、代码实现2.4、小结 三、求一个论坛…