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 开发注入强大动力,深入理解其原理和流程,有助于开发者在开发领域游刃有余。后续可探索定制化自动装配,拓展框架应用边界,激发更多创新可能。

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

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

相关文章

C++中的字符串实现

短字符串优化(SSO) 实现1 实现2 写时复制 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstdio> #include<cstring> #include<cstring> using std::cout; using std::endl;// 引用计数存放的位置 // 1. 存放在栈上 --- 不行 // 2. 存…

Linux 基本使用和程序部署

1. Linux 环境搭建 1.1 环境搭建方式 主要有 4 种&#xff1a; 直接安装在物理机上。但是Linux桌面使用起来非常不友好&#xff0c;所以不建议。[不推荐]。使用虚拟机软件&#xff0c;将Linux搭建在虚拟机上。但是由于当前的虚拟机软件(如VMWare之类的)存在一些bug&#xff…

环网冗余CAN转光纤 CAN光端机在风电项目应用

在风力发电项目中&#xff0c;所有的风机内部的状态都需要能够在中控室备被监控到&#xff0c;不论是风机的工作状态还是风机内部的消防状态&#xff0c;以便中控室的工作人员都够根据观测到的信息及时的做出反应&#xff0c;避免造成重大损失。 通常风机的工作信息通过将网口…

ubuntu 如何重装你的apt【apt-get报错: symbol lookup error/undefined symbol】

副标题:解决error:apt-get: symbol lookup error: /lib/x86_64-linux-gnu/libapt-private.so.0.0: undefined symbol: _ZNK13pkgTagSection7FindULLENS_3KeyERKy, version APTPKG_6.0 文章目录 问题描述报错分析解决方案:重装你的apt1、查看你的ubuntu版本2、下载适配你的ap…

网络管理 详细讲解

讲一下之前获取CPU的&#xff0c;其余的原理和这个一样 python代码 app.route(/cpu/) def cpu_used():cpuoidObjectType(ObjectIdentity(myOIDs[cpu_loads]))ret getTableRows((cpuoid,))cpuload0for i in ret:cpuload i[0]print(cpuload)return {cpu:cpuload} var dom do…

用Python PySide6 复刻了两软件UI 做下练习

图样 1 代码 1&#xff1a; # -*- coding: utf-8 -*-import sys from PySide6.QtCore import (QCoreApplication, QMetaObject, QRect, QDate) from PySide6.QtGui import QIcon, QPixmap, QColor from PySide6.QtWidgets import (QApplication, QDialog, QLineEdit, QPushBut…

【day14】异常处理与Object类深入解析

【day13】回顾 在深入探讨异常处理与Object类之前&#xff0c;让我们回顾一下【day13】中的关键内容&#xff1a; 权限修饰符&#xff1a; public&#xff1a;最广的访问范围&#xff0c;任何地方都可以访问。protected&#xff1a;在同包和子类中可以访问。默认&#xff08;无…

题解 洛谷 Luogu P1135 奇怪的电梯 广度优先搜索 BFS C/C++

题目传送门&#xff1a; P1135 奇怪的电梯 - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/problem/P1135思路&#xff1a; 一道比较裸的 BFS&#xff0c;就是把走迷宫每次搜周围相邻四格&#xff0c;改成了楼层每次搜上下方向的某层而已 感觉这个题难度只有普及- …

苏黎世联邦理工学院与加州大学伯克利分校推出MaxInfoRL:平衡内在与外在探索的全新强化学习框架

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ

Q1、统计符合条件长度为3的子数组数目 1、题目描述 给你一个整数数组 nums &#xff0c;请你返回长度为 3 的子数组&#xff0c;满足第一个数和第三个数的和恰好为第二个数的一半。 子数组 指的是一个数组中连续 非空 的元素序列。 2、解题思路 我们需要在给定的数组 nums…

【RAG实战】Prompting vs. RAG vs. Finetuning: 如何选择LLM应用选择最佳方案

在构建基于大型语言模型&#xff08;LLM&#xff09;的应用时&#xff0c;通常不可能立即使用模型而无需任何调整。为了保持高实用性&#xff0c;我们可以选择以下几种方法之一&#xff1a; Prompt Engineering&#xff08;提示工程&#xff09;Fine-tuning&#xff08;微调&a…

Odoo:免费开源ERP的AI技术赋能出海企业电子商务应用介绍

概述 伴随电子商务的持续演进&#xff0c;客户对于便利性、速度以及个性化服务的期许急剧攀升。企业务必要探寻创新之途径&#xff0c;以强化自身运营&#xff0c;并优化购物体验。达成此目标的最为行之有效的方式之一&#xff0c;便是将 AI 呼叫助手融入您的电子商务平台。我们…

如何打造用户友好的维护页面:6个创意提升WordPress网站体验

在网站运营中&#xff0c;无论是个人博主还是大型企业网站的管理员&#xff0c;难免会遇到需要维护的情况。无论是服务器迁移、插件更新&#xff0c;还是突发的技术故障&#xff0c;都可能导致网站短暂无法访问。这时&#xff0c;设计维护页面能很好的缓解用户的不满&#xff0…

定位方式:css

使用相对路径 div ul #div下的所有ul&#xff0c;空格表示相对路径&#xff08;这个实际中用的多一些&#xff09; 绝对路径-一般不用绝对路径 html>head>div&#xff0c;“>”表示根路径 使用class名称定位 使用.表示 使用id定位 使用#表示 使用属性定位 [属性名…

【YashanDB知识库】jdbc查询st_geometry类型的数据时抛出YAS-00101错误

本文内容来自YashanDB官网&#xff0c;原文内容请见 https://www.yashandb.com/newsinfo/7802956.html?templateId1718516 问题现象 某客户的业务在通过YashanDB jdbc驱动查询含有st_geometry列的数据时&#xff0c;报如下异常&#xff1a;YAS-00101 cannot allocate 0 byte…

[Unity]Unity集成NuGet-连接mysql时的发现

本次使用软件信息&#xff1a; Unity&#xff1a;2022.3.34f1c1。 mysql&#xff1a;mysql 8.0 安装于远程服务器。 使用插件&#xff1a;NuGetForUnity4.1.1.unitypackage 点击名称可前往下载界面。 一、导入插件 打开Unity的时候可直接双击导入道assets。导入后如下图&…

重温设计模式--外观模式

文章目录 外观模式&#xff08;Facade Pattern&#xff09;概述定义 外观模式UML图作用 外观模式的结构C 代码示例1C代码示例2总结 外观模式&#xff08;Facade Pattern&#xff09;概述 定义 外观模式是一种结构型设计模式&#xff0c;它为子系统中的一组接口提供了一个统一…

HDR视频技术之十一:HEVCH.265 的 HDR 编码方案

前文我们对 HEVC 的 HDR 编码优化技术做了介绍&#xff0c;侧重编码性能的提升。 本章主要阐述 HEVC 中 HDR/WCG 相关的整体编码方案&#xff0c; 包括不同应用场景下的 HEVC 扩展编码技术。 1 背景 HDR 信号一般意味着使用更多比特&#xff0c;一般的 HDR 信号倾向于使用 10…

shardingsphere分库分表项目实践1-让shardingsphere运行起来

学习新技术最快的方式就是&#xff1a; 1. 先找一个比较完善的demo跑起来 2. 弄清楚用法&#xff1a;配置、原理、使用场景 3. 移植到自己项目上&#xff0c;按照自己需求进行修改优化。 找demo项目的方法&#xff1a;优先去官方git库找&#xff0c;如果没有或者过于简单那么…

【QSS样式表 - ⑥】:QPushButton控件样式

文章目录 QPushBUtton控件样式QSS示例 QPushBUtton控件样式 常用子控件 常用伪状态 QSS示例 代码&#xff1a; QPushButton {background-color: #99B5D1;color: white;font-weigth: bold;border-radius: 20px; }QPushButton:hover {background-color: red; }QPushButton:p…