当前位置: 首页 > news >正文

SpringBoot 自动装配原理及源码解析

目录

一、引言

二、什么是 Spring Boot 的自动装配

三、自动装配的核心注解解析

3.1 @SpringBootApplication 注解

(1)@SpringBootConfiguration:

(2)@EnableAutoConfiguration:

(3)@ComponentScan:

3.2 条件装配(@Conditional 系列注解)

示例:DataSourceAutoConfiguration

四、自动配置的工作流程

五、SpringBoot 自动装配的实际案例

六、好处


一、引言

        在 Java 开发领域,Spring Boot 占据着重要地位,其自动装配机制对传统开发模式产生了巨大变革。过去,传统 Spring 项目配置繁杂,极易出现版本冲突与配置错误,耗费开发者大量精力。而 Spring Boot 引入自动装配功能后,项目近乎可 “零配置” 启动,开发者能将主要精力集中于业务逻辑的实现,极大提高了开发效率。接下来,我们深入剖析 Spring Boot 自动装配背后的原理。

二、什么是 Spring Boot 的自动装配

        Spring Boot 自动装配是一套智能且高效的依赖注入与配置协调系统,遵循 “约定优于配置” 的原则。在项目启动阶段,它能够自动识别类路径下的各类组件及配置信息,并依据预先设定的精细规则完成装配任务。

三、自动装配的核心注解解析

3.1 @SpringBootApplication 注解

自动配置的起点通常是 @SpringBootApplication 注解,它是一个组合注解,包含了三个重要注解。

@SpringBootApplication
public class SpringBootDemo1031Application {public static void main(String[] args) {SpringApplication.run(SpringBootDemo1031Application.class, args);}
}

(1)@SpringBootConfiguration

本质等同于@Configuration,为自动装配的配置环节搭建基础框架,保障配置步骤有序进行

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

        它是是自动配置的核心,通过@Import(AutoConfigurationImportSelector.class)引入AutoConfigurationImportSelector。

AutoConfigurationImportSelector 类的继承体系如下:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}public interface DeferredImportSelector extends ImportSelector {}public interface ImportSelector {String[] selectImports(AnnotationMetadata var1);
}

        可以看出,AutoConfigurationImportSelector类实现了ImportSelector接口,也就实现了这个接口中的selectImports方法,该方法主要用于获取所有符合条件的类的全限类名,这些类需要被加载到IOC容器中。 

public String[] selectImports(AnnotationMetadata annotationMetadata) {// 1.检查是否启用自动配置if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {// 2.获取所有需要装配的beanAutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
}

getAutoConfigurationEntry方法通过一系列步骤,包括检查自动配置是否启用、获取候选配置、去除重复项、获取排除配置、检查排除的类是否有效、移除排除项、过滤配置,最终生成一个包含自动配置类和排除配置类的AutoConfigurationEntry对象。这个方法是Spring Boot自动配置功能的核心,它确保了只有符合条件的自动配置类被加载到Spring应用上下文中。

/*** 获取自动配置入口信息,包括需要加载的自动配置类和需要排除的配置类。** @param annotationMetadata 当前注解的元数据,提供了关于注解的信息,用于决定哪些自动配置类应该被导入。* @return 包含自动配置类和排除配置类的AutoConfigurationEntry对象。*/
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {// 1. 如果自动配置没有被启用,则返回一个空的AutoConfigurationEntry对象if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {// 2. 从注解元数据中获取注解属性AnnotationAttributes attributes = this.getAttributes(annotationMetadata);// 3. 获取所有候选的自动配置类名List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);// 4. 去除候选配置中的重复项configurations = this.removeDuplicates(configurations);// 获取需要被排除的自动配置类名Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);// 检查排除的类是否在候选配置中,如果不在,则抛出异常this.checkExcludedClasses(configurations, exclusions);// 从候选配置中移除排除项configurations.removeAll(exclusions);// 使用ConfigurationClassFilter过滤候选配置configurations = this.getConfigurationClassFilter().filter(configurations);// 触发自动配置导入事件,通知所有监听器自动配置类即将被导入this.fireAutoConfigurationImportEvents(configurations, exclusions);// 创建并返回一个新的AutoConfigurationEntry对象,包含过滤后的配置和排除配置return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}
}

接下来,我们debug看一下具体步骤:

  • 步骤1:判断自动装配开关是否打开,默认spring.boot.enableautoconfiguration=true,可以在application.properties或者application.yml中设置 。
  • 步骤2:获取EnableAutoConfiguration注解中的exclude 和excluedeName

  • 步骤3:获取需要自动装配的所有配置类,读取META-INF/spring.factories 

自动配置类的信息通常位于spring-boot-autoconfigure模块的META-INF/spring.factories文件中。这个文件列出了所有可以被自动加载的配置类,当Spring Boot应用启动时,AutoConfigurationImportSelector会读取这个文件,并根据其中的信息将相应的自动配置类导入到应用上下文中。

  • 步骤4:在spring boot中,spring.factories文件中列出了许多自动配置类,这并不意味着每次应用启动时所有这些配置都会被加载。Spring Boot采用一种称为条件配置的机制,使得只有在特定条件满足时,相关的自动配置类才会被激活和加载。

(3)@ComponentScan

        负责搜索项目中的组件,收集散落的组件,为后续装配工作提供资源支持,确保所需组件无遗漏。

3.2 条件装配(@Conditional 系列注解)

Spring Boot并非盲目加载所有自动配置类,每个自动配置类通常都会运用@Conditional系列注解来实现有条件的加载,这极大地优化了资源配置,让自动装配更贴合项目实际需求。最常见的条件注解有:

  • @ConditionalOnClass:当类路径中存在某个类时才生效。
  • @ConditionalOnMissingBean:当 Spring 上下文中不存在某个 Bean 时才生效。
  • @ConditionalOnProperty:当某个配置属性满足特定条件时才生效。
  • @ConditionalOnBean:当 Spring 上下文中存在某个 Bean 时才生效。

示例:DataSourceAutoConfiguration

Spring Boot 中DataSourceAutoConfiguration 是配置数据源的自动配置类,它的源码如下:

@Configuration
@ConditionalOnClass(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({DataSourcePoolMetadataProvidersConfiguration.class,DataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic DataSource dataSource(DataSourceProperties properties) {return properties.initializeDataSourceBuilder().build();}
}
  • @ConditionalOnClass(DataSource.class):只有当类路径下存在 DataSource 类时,才进行数据源的自动配置。
  • @ConditionalOnMissingBean:如果 Spring 上下文中没有其他 DataSource Bean,则自动配置一个。

        只有当这些条件满足时,DataSourceAutoConfiguration才会被实例化和执行,这意味着Spring Boot在启动过程中,并不会盲目的加载spring.factories中的每一个自动配置类,而是基于运行环境和应用的配置智能选择激活配置。

四、自动配置的工作流程

1. 收集自动配置类

启动时,AutoConfigurationImportSelector 从 spring.factories 文件中读取所有的自动配置类,并通过 @Import 导入这些类。

2. 条件检查

自动配置类的加载不是无条件的,Spring Boot 会根据 @Conditional 注解进行条件检查,确保只有符合条件的自动配置类才会生效。

3. 注入所需的 Bean

一旦自动配置类通过条件检查,Spring Boot 就会根据这些配置类注册所需的 Bean。例如,DataSourceAutoConfiguration 会自动配置数据源相关的 Bean。

4. 允许用户覆盖自动配置

自动配置并不是强制的。用户可以通过显式声明自己的 Bean 来覆盖自动配置的默认行为。例如,如果用户在自己的配置类中定义了 DataSource,那么 Spring Boot 就不会再自动配置数据源。

五、SpringBoot 自动装配的实际案例

1. Web 应用自动配置

在 Spring Boot Web 应用中,DispatcherServletAutoConfiguration 负责自动配置 Spring MVC 的核心组件,例如 DispatcherServletRequestMappingHandlerMapping 等。

  • 如果项目中存在 spring-web 依赖,那么 DispatcherServletAutoConfiguration 会自动加载。
  • 如果没有手动定义 DispatcherServlet,Spring Boot 会自动创建一个 DispatcherServlet 并配置到 Spring 容器中。

2. 数据库连接池自动配置

Spring Boot 还会自动配置数据库连接池(如 HikariCP、Tomcat JDBC 等),这依赖于项目中的 spring-boot-starter-data-jpa 或者 spring-boot-starter-jdbc 依赖。

  • DataSourceAutoConfiguration 和 DataSourceProperties 共同负责自动配置数据源。
  • 如果类路径中存在连接池类(如 DruidDataSource),那么 Spring Boot 就会自动配置连接池。

六、好处

1. 提高开发效率

开发者摆脱繁琐配置工作,无需反复查阅文档、调试配置,节省大量时间,得以聚焦业务功能迭代,在市场竞争中抢占先机。

2. 降低学习成本

对于初涉 Spring 技术栈的新手,复杂的 Spring 配置体系曾令人望而却步。自动装配机制降低入门难度,使其无需陷入配置困境,轻松上手融入团队。

3. 保证一致性

自动装配由 Spring Boot 框架统一管理控制,遵循统一约定,不同项目结构与配置趋于一致,便于团队协作、代码维护与知识传承,保障项目生命周期稳健延续。

        总之,Spring Boot 自动装配机制为 Java 开发注入强大动力,深入理解其原理和流程,有助于开发者在开发领域游刃有余。后续可探索定制化自动装配,拓展框架应用边界,激发更多创新可能。

相关文章:

SpringBoot 自动装配原理及源码解析

目录 一、引言 二、什么是 Spring Boot 的自动装配 三、自动装配的核心注解解析 3.1 SpringBootApplication 注解 &#xff08;1&#xff09;SpringBootConfiguration&#xff1a; &#xff08;2&#xff09;EnableAutoConfiguration&#xff1a; &#xff08;3&#xf…...

Craft CMS 模板注入导致 Rce漏洞复现(CVE-2024-56145)(附脚本)

0x01 产品描述: ‌Craft CMS‌ 是一个灵活且强大的内容管理系统(CMS),专为创意团队和开发人员设计,提供高度可定制、直观且性能优越的网站和内容管理解决方案。它以用户友好的界面、强大的插件生态系统以及支持现代web开发最佳实践的特性而闻名‌0x02 漏洞描述: 由于模板…...

Next.js 新手容易犯的错误 _ 加载与缓存管理的关键(5)

1 错误地处理搜索参数&#xff08;Search Params&#xff09; 问题是什么&#xff1f; 在 Next.js 中&#xff0c;搜索参数指的是 URL 中用 ?keyvalue 表示的部分&#xff0c;比如 https://example.com/products?colorred 中的 colorred。这通常用于过滤、排序或选择某些选…...

/etc/fstab 文件学习systemd与该文件关系

文章目录 一、文件字段1.1、设备标识1.2、挂载点1.3、文件系统类型1.4、挂载选项1.5、dump1.5、fsck顺序 二、/etc/fstab 与systemd 的关系2.1、/etc/fstab 与systemd 的关系2.2、systemd 之前/etc/fstab生效过程2.3、systemd 时代/etc/fstab生效过程 三、相关知识3.1、如何更具…...

从源码分析swift GCD_DispatchGroup

前言&#xff1a; 最近在写需求的时候用到了DispatchGroup&#xff0c;一直没有深入去学习&#xff0c;既然遇到了那么就总结下吧。。。。 基本介绍&#xff1a; 任务组&#xff08;DispatchGroup&#xff09; DispatchGroup 可以将多个任务组合在一起并且监听它们的完成状态。…...

25计软新增考研院校!或可捡漏上岸!

C哥专业提供——计软考研院校选择分析专业课备考指南规划 新增的计算机与软件工程考研院校为考研同学带来了多方面的机遇&#xff0c;这些机遇不仅体现在过国家线后可能面临的更低竞争压力&#xff0c;还包括更多元化的教育选择和更广阔的就业前景&#xff1a; 一、降低竞争压…...

C# 线程安全集合

文章目录 引言一、ConcurrentBag<T>二、ConcurrentQueue<T>三、ConcurrentStack<T>四、ConcurrentDictionary<TKey, TValue>五、总结引言 在多线程编程环境中,多个线程可能同时访问和操作集合数据。如果使用普通集合,很容易引发数据不一致、错误结果…...

箱包发霉怎么处理 箱包发霉处理修复方法

箱包发霉怎么处理&#xff1f;箱包不仅是我们出行的必需品&#xff0c;更是承载着个人风格与品味的时尚配饰。然而箱包工厂生产的箱包&#xff0c;在潮湿多变的环境中&#xff0c;箱包很容易成为霉菌滋生的温床&#xff0c;尤其是那些长时间储存的箱包&#xff0c;更是霉菌的“…...

【每日学点鸿蒙知识】Charles抓包、lock文件处理、WebView组件、NFC相关、CallMethod失败等

1、HarmonyOS系统中如何使用Charles抓包&#xff1f; 在HarmonyOS操作系统中&#xff0c;使用Charles进行抓包的步骤如下&#xff1a; 在Charles中设置代理。 首先&#xff0c;在Charles的菜单栏上选择“Proxy”→“Proxy Settings”&#xff0c;然后填入代理端口&#xff0…...

【异常】GL-SFT1200路由器中继模式,TL-CPE1300D无法搜寻5G网问题分析

【异常】GL-SFT1200路由器中继模式,TL-CPE1300D无法搜寻5G网问题 情况实验结论情况 在用GL-SFT1200路由器切换中继模式时,由于web密码忘却,需要重置,但根据官网使用手册,或者对应的中文版手册,重置失败。通过跟商家联系,进行uboot刷机,提供了指导文档,尝试后刷机成功…...

LINUX--shell

函数 格式&#xff1a; func() { command } function 关键字可写&#xff0c;也可不写。 示例 1&#xff1a; #!/bin/bash func() { #定义函数 echo "Hello $1" } func world #执行主文件 # bash test.sh Hello world 数组 数组是相…...

TCP常见问题

文章目录 一、两种状态图二、常见问题1、MSL是什么 3、为何等待2MSL3、为何三次握手&#xff0c;不握手、握手一次、两次行吗4、为何四次挥手&#xff0c;三次行吗&#xff0c;两次行吗 一、两种状态图 四次挥手 二、常见问题 1、MSL是什么 MSL是Maximum Segment Lifetime的英…...

OpenCV学习——图像融合

import cv2 as cv import cv2 as cvbg cv.imread("test_images/background.jpg", cv.IMREAD_COLOR) fg cv.imread("test_images/forground.png", cv.IMREAD_COLOR)# 打印图片尺寸 print(bg.shape) print(fg.shape)resize_size (1200, 800)bg cv.resize…...

网速、续航双在线!2024随身WiFi品牌精选推荐!格行按键切三网值得买吗?

随身wifi这个东西大家用的还是蛮多的&#xff0c;特别是一些户外工作的人员&#xff0c;往往都需要配备一个随身wifi&#xff0c;这样户外工作的时候才有网络&#xff0c;工作才会比较方便一些。今天就来盘点2024年热门随身wifi哪个牌子的好用&#xff1f; 1.华为&#xff1a;通…...

ubuntu18.04连接不上网络问题

现象&#xff1a;右上角的网络图标消失&#xff0c;仅剩输入法、音量和开关图标&#xff0c;ifconfig只显示本地回环 原因&#xff1a;网络适配器未开启 解决&#xff1a; 1. 查看网络状态&#xff1a;cat /var/lib/NetworkManager/NetworkManager.state 这里显示是false&a…...

访谈积鼎科技总经理:国产CFD软件发展与未来趋势展望

傅彦国&#xff0c;上海积鼎信息科技有限公司创始人 记者&#xff1a;请傅总介绍下我国流体仿真行业的发展现状是怎样的&#xff1f; 傅彦国&#xff1a;自2018年政府加大了对核心技术自主研发的支持力度&#xff0c;国产CFD软件逐渐步入发展正轨。 首先&#xff0c;从市场规…...

【Linux知识】exec命令行详解

文章目录 概述主要用途和 bash 有什么区别&#xff1f; 概述 在 Linux 系统中&#xff0c;exec 命令用于执行一个可执行文件&#xff0c;替换当前进程的映像。也就是说&#xff0c;当你在终端中使用 exec 命令后&#xff0c;当前的 shell 会被替换为 exec 指定的程序&#xff…...

【学术小白的学习之路】基于情感词典的中文句子情感分析(代码词典获取在结尾)

【学术小白的学习之路】基于情感词典的情感分析 1.基础函数1.1 判断情感词的否定词数量1.2 导入情感词典1.3 切分句子1.3.1为什么划分1.3.2 划分代码 1.4 完整代码 2.导入词典3.中文情感分析算法思路4.1情感词获取思路4.2 计算情感分值4.3 得分的归一化处理 4.实证5.总结 本文的…...

Linux 中 grep、sed、awk 命令

1. awk&#xff1a;强大的文本分析工具 awk&#xff0c;全称“Awk语言”&#xff0c;是一种专门用于处理文本文件的语言。它不仅能够根据关键字匹配某一行&#xff0c;还能进行复杂的文本分析和处理。awk的语法简洁明了&#xff0c;功能强大&#xff0c;是文本处理领域的佼佼者…...

一起考高项啊--现代化基础设施(工业互联网)

1、工业互联网的内涵和外延 工业互联网不是互联网在工作的简单应用&#xff0c;是具有更为丰富的内涵和外延。 它既是工业数字化、网络化、智能化转型的基础设施&#xff0c;也是互联网、大数据、人工智能与实体经济深度融合的应用模式&#xff0c;同时也是一种新业态、新产业…...

python学opencv|读取图像(二十)使用cv2.circle()绘制圆形进阶

【1】引言 前序已经掌握了使用cv2.circle()绘制圆形的基本操作&#xff0c;相关链接为&#xff1a; python学opencv|读取图像&#xff08;二十&#xff09;使用cv2.circle()绘制圆形-CSDN博客 由于圆形本身绘制起来比较简单&#xff0c;因此可以自由操作的空间也就大&#x…...

期权懂|如何减小个股期权交易中的风险?

锦鲤三三每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 如何减小个股期权交易中的风险&#xff1f; 一、选择合适的期权合约 &#xff08;1&#xff09;选择活跃的期权合约&#xff1a;投资者应优先选择交易活跃的期权合约。交易活跃的…...

ubuntu20.04 wget下载--段错误 (核心已转储)

用wget下载时总是在快下载完成时遇到段错误 untu2004-9.1.0_1.0-1_am 99%[> ] 1.63G 3.11MB/s 剩余 1s s段错误 (核心已转储)有以下两种解决方法&#xff1a; 1.手动下载 wget后面就是要下载的资源的链接&#xff0c;直接复制到浏览器中下载即可 如&#xff1a…...

怎么样保持mysql和redis数据一致性

保持 MySQL 和 Redis 数据的一致性是一个常见的挑战,因为 MySQL 是传统的关系型数据库,而 Redis 是内存数据库,通常用于缓存和高性能存储。这两者的数据更新方式不同,特别是当 Redis 用作缓存时,可能会存在缓存和数据库之间的数据不一致问题。为了保持数据一致性,通常可以…...

剑指Offer|LCR 013. 二维区域和检索 - 矩阵不可变

LCR 013. 二维区域和检索 - 矩阵不可变 给定一个二维矩阵 matrix&#xff0c;以下类型的多个请求&#xff1a; 计算其子矩形范围内元素的总和&#xff0c;该子矩阵的左上角为 (row1, col1) &#xff0c;右下角为 (row2, col2) 。 实现 NumMatrix 类&#xff1a; NumMatrix(…...

aosp15 - Activity生命周期切换

本文探查的是&#xff0c;从App冷启动后到MainActivity生命周期切换的系统实现。 调试步骤 在com.android.server.wm.RootWindowContainer#attachApplication 方法下断点&#xff0c;为了attach目标进程在com.android.server.wm.ActivityTaskSupervisor#realStartActivityLock…...

vxe-table 虚拟滚动的动态响应

虚拟滚动主要是在有限范围内渲染想要显示的数据&#xff0c;主要体现在懒加载数据和动态渲染上。如何提高虚拟滚动的操作性呢&#xff1f;请看本章解析 1.什么是虚拟滚动&#xff1f;代码如何实现&#xff1f; VXE-Table提供了一种名为“虚拟滚动”的功能&#xff0c;该功能可…...

quasar dev 命令卡住很久

别以为这是一个瞬间的截图&#xff0c;其实停留在这里很久很久。 折腾挺久&#xff0c;无论npm run dev:proxy还是 quasar dev&#xff0c;都是一样的情况。 最终解决办法&#xff1a; 有语法问题&#xff0c;通过 quasar build 命令暴露出来错误所在的行数。...

黑盒RCE测试 异或测试

前言 了解了漏洞的原理之后就需要知道 他在哪能出现 并且被利用 这个还是很重要的 异或测试 使用异或&#xff08;XOR&#xff09;运算进行加密解密的原理_异或加密-CSDN博客 异或测试是在 白盒内执行的 一个例题看一下 输入什么都是会报错 这种情况就需要使用 异或计…...

kotlin中泛型中in和out的区别

概念含义 in关键字&#xff08;逆变&#xff09; 在Kotlin泛型中&#xff0c;in关键字主要用于定义逆变&#xff08;Contravariance&#xff09;。它表示一个泛型类型参数可以是指定类型或者它的超类型。简单来说&#xff0c;就是对于类型A和B&#xff0c;如果A是B的子类型&…...