【Spring Boot】自动配置源码解析

news2025/2/23 20:00:41

目录

  • Spring-Boot-Starter
    • 一、准备配置类和 Bean 对象
    • 二、自动配置条件依赖
    • 三、Bean 的参数获取
      • 3.1 @EnableConfigurationProperties 注解
      • 3.2 @ConfigurationProperties 注解
    • 四. Bean 的发现
      • 4.1 自己项目的 Bean 扫描
      • 4.2 jar 包的 Bean 扫描
    • 五. Bean 的加载
  • 自动配置总结

Spring-Boot-Starter

一、准备配置类和 Bean 对象

Spring Boot 提供了两个注解:

  • @Configuration:Spring 提供的配置类注解,作用在类上,代表整个类是个 Spring 配置类,对照传统的 Spring XML 配置文件
  • @Bean:作用于方法上,代表此方法的返回值(对象)将会被 Spring 容器所管理,从而完成 Bean 的自动注册。

这两个组合起来搭配可以完美的代替传统的 Spring XML 配置文件,并给 Spring Boot 的自动配置提供基本数据体。

二、自动配置条件依赖

有些情况下自动配置类并不是在任何条件下都能生效的,此时我们需要制定自动配置生效的条件,可以使用 Spring Boot 提供的注解来指定生效条件。

这些注解是 spring boot 特有的,常见的条件依赖注解有:

注解 功能说明

  • @ConditionalOnBean 仅在当前上下文中存在某个 bean 时,才会实例化这个 Bean
  • @ConditionalOnClass 某个 class 位于类路径上,才会实例化这个 Bean
  • @ConditionalOnExpression 当表达式为 true 的时候,才会实例化这个 Bean
  • @ConditionalOnMissingBean 仅在当前上下文中不存在某个 bean 时,才会实例化这个 Bean
  • @ConditionalOnMissingClass 某个 class 在类路径上不存在的时候,才会实例化这个 Bean
  • @ConditionalOnNotWebApplication 不是 web 应用时才会实例化这个 Bean
  • @AutoConfigureAfter 在某个 Bean 完成自动配置后实例化这个 Bean
  • @AutoConfigureBefore 在某个 Bean 完成自动配置前实例化这个 Bean

三、Bean 的参数获取

举个例子,例如在 Spring Boot Web 项目中,我们经常会导入 MyBatis 相关的依赖,帮助我们与数据库打交道,那么在传统的 Spring 项目中,我们一般会在 Spring 容器配置 XML 文件中去使用 标签生成相关数据源(DataSource),那么这个 DataSource 需要我们提供数据库连接参数:driver、url、username、password 这四个最基本的参数,这些数据可能放在一个叫做 db.properties 文件中,这种文件我们称为外部数据源文件,在 Spring 配置文件中声明:<context:property-placeholder location=“classpath:db.properties”/>

这样就可以引入文件中的配置参数了,从而赋值给 DataSource 这个 Bean 所需要的属性参数。最后完成对象初始化。

这个过程在传统 Spring 开发,无疑是略显繁琐,如果在某些我们需要自定义类和大量参数属性从外部文件引入,这个时候 properties 文件格式也比较复杂,文件可能较多,在初始化 Bean 时,需要手写大量的属性赋值。

那么 Spring Boot 提供了注解帮助我们减小开发量,更加规范 Bean 参数的获取方式。

默认情况下我们 Bean 的参数配置在 application.yml 文件中,使用 YAML 文件格式定义,比 properties 文件更有层级感,更简约。

搭配 @EnableConfigurationProperties、@ConfigurationProperties 这两个注解可以直接实现自动配置类的 Bean 参数获取。

3.1 @EnableConfigurationProperties 注解

这个注解使用情况:自动配置类中需要从外部文件获取参数,来进行初始化。

在注解中指定一个类,这个时候可以配置类可以在这个类中获取到外部文件的参数,交给配置类中的 Bean 进行初始化。

3.2 @ConfigurationProperties 注解

注解使用情况:从外部文件获取参数信息,加载到自身类属性中,给 Spring 配置类提供外部数据来源,外部数据文件通常指的是 application.yml。

在注解中指定从 application.yml 文件获取的前缀,例如 @ConfigurationProperties(prefix=“spring.datasource”),会获取以这个字符串为前缀的所有参数进行自动匹配赋值。

所以可以看出两个注解的关系是:

@EnableConfigurationProperties 注解作用在配置类中,并且使得该注解指定的数据文件类中的 @ConfigurationProperties 注解生效。

四. Bean 的发现

4.1 自己项目的 Bean 扫描

在写 Spring Boot 项目时,一般在项目的代码的根目录会有一个 Spring Boot 启动类:xxxApplication.java,这个类被 @SpringBootApplication 注解修饰标记成 Spring Boot 项目的启动类。

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

此时再来看看如何完成 Bean 扫描,我们需要查看 @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 {
    //...
}

我们重点查看 @SpringBootConfiguration 注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

可以看到这个注解被熟悉的 @Configuration 注解修饰。@SpringBootConfiguration 应用标注在某个类上说明这个类是SpringBoot 的主配置类,SpringBoot 需要运行这个类的 main 方法来启动 SpringBoot 应用。

底层 Spring Boot 会帮我们将启动类的当前路径包以及子包的所有 Spring 组件(可能需要 @ComponentScan注解去做组件扫描)以及 Bean 扫描初始化。暂时只说浅层的流程,后续会深入 Spring 源码学习。

4.2 jar 包的 Bean 扫描

那么前面聊了自己项目的 Bean 扫描,且 Spring Boot 默认扫描启动类所在包下的主类与子类的所有组件,其中并没有包括项目依赖包中的类,那么这些类是如何被 Spring Boot 发现的呢?

这就是第二个主要注解:@EnableAutoConfiguration,开启自动配置:

这里引入其他博客的理解,觉得这几句话简单易懂:

@EnableAutoConfiguration 的作用
简单点说就是 Spring Boot 根据依赖中的 jar 包,自动选择实例化某些配置,配置类必须有 @Configuration 注解。

说白了,还是实例化对象,只是实例化的是依赖包中的类。

另外,我们也可以按照自动装配的规范自己定义装配的类。

接下来查看一下注解源码:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    //...
}

主要看 @Import({AutoConfigurationImportSelector.class}),这个注解导AutoConfigurationImportSelector.class 这个类(如果是其他版本,可能会是 @EnableAutoConfigurationImportSelector 这个是子类)。

image-20230924102323579

我们找到 getCandidateConfigurations() 方法,这个方法就是用来加载依赖所需要的自动配置相关。

看到 SpringFactoriesLoader.loadFactoryNames() 的源码:

image-20230924102840726

其他版本可能是只有 loadFactoryNames() 方法,但是我们主要关注 classLoader.getResources() 方法中的常量:

image-20230924103000135

很明显这个方法是用来加载资源文件,而这个 Spring 工厂资源的路径就是依赖中自动配置的相关路径,根据这个路径找到需要自动配置的类,最后完成依赖的自动配置。我们导入 mybatis-spring-boot-starter 依赖看看这个 META-INF/spring.factories 里边是怎么样的:

image-20230924103430699

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

简单概括的流程:Spring Boot 会根据 jar 包的 META-INF/spring.factories 文件的配置进行自动装配,装配的流程是 SpringFactoriesLoader.loadFactoryNames() 方法顶层实现的(底层实现需深入源码),而开始外部自动装配的注解是:@SpringBootApplication 注解中的 @Import({AutoConfigurationImportSelector.class})

主导整个过程。

五. Bean 的加载

在 Spring Boot 中将一个普通类交给 Spring 容器管理,通常有以下几个方法:

使用 @Configuration 配合 @Bean 注解使用(配置类)。

使用 @Controller、@Service、@Repository、@Component 注解标注类并且使用 @ComponentScan 自动扫描(组件扫描)。

使用 @Import 方法(加载外部依赖的类)。

在上面可以看到 Spring Boot 实现自动配置使用的是 @Import 注解这种方式。

AutoConfigurationImportSelector 类的 selectImports() 方法(其中调用了 getAutoConfigurationEntry() 方法主要过程)返回一组从 META-INF/spring.factories 文件中读取的 Bean 的全限定名,这样 Spring Boot 就可以加载到这些 Bean 并完成实例的初始化工作。

自动配置总结

经过前面的分析,将自动配置的关键步骤以及对应注解抽取出来:

定义需要自动装配的类信息:@Configuration、@Bean,Spring Boot 配置类。

设置自动配置条件依赖:@Conditional。

将外部配置文件读取并封装成 Bean,让配置类读取参数:@EnableConfigurationProperties、@ConfigurationProperties。

实现 Bean 的发现与加载:@EnableAutoConfiguration、@Import。

以上的内容是基于其他相关博客内容的基础,进行自己的学习记录,接下来需要自定义一个 Spring Boot Starter 来进一步加深理解,后续可能还需要对 Spring 、Spring Boot 的源码进行学习。

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

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

相关文章

Linux系统编程——生产者消费者模型

目录 一&#xff0c;模型介绍 1.1 预备知识&#xff08;超市买东西的例子&#xff09; 1.2 模型介绍 1.3 CP模型特点 二&#xff0c;基于阻塞队列的CP模型 2.1 介绍 2.2 阻塞队列的实现 2.3 主函数实现 2.4 效果展示 三&#xff0c;POSIX信号量 3.1 信号量原理 3…

Date已不再推荐?为什么我们需要新的 Java 日期时间 API?(LocalDate、LocalDateTime、LocalTime 、Instant)

日期时间 API 是 Java 8 版本的最大功能之一。Java 从一开始就缺少一致的日期和时间方法&#xff0c;而 Java 8 日期时间 API 是对核心 Java API 的一个受欢迎的补充。 为什么我们需要新的 Java 日期时间 API&#xff1f; 在开始研究 Java 8 日期时间 API 之前&#xff0c;让我…

蛋仔派对S18赛季攻略

本人蛋仔名&#xff1a;Z周明昊帅哥&#xff08;稍微自恋了一点&#xff09;&#x1f60e; 没夺冠的心情&#xff0c;请看下图&#xff1a; 呜呜呜…… 蛋仔五小只人形&#xff1a; 观看视频 完结撒花^_^ BUY&#xff01;&#xff01;&#xff01;

31-库文件的制作与使用——静态库文件与动态库文件

31-库文件的制作与使用——静态库文件与动态库文件 一、库文件介绍 库文件是在计算机编程中用来存放变量、函数和类的文件&#xff0c;提供给开发者开箱即用的资源。库文件分为静态库和动态库两种&#xff0c;二者在程序链接阶段的行为不同&#xff1a; 静态库&#xff1a;在…

HALCON如何添加外部函数

1、在HALCON菜单栏中点击【编辑】选择【参数选择】或者 点击【函数】选择【管理函数】进入到参数窗口&#xff1b; 2、在参数窗口下依次选择【函数】、【目录】和【添加】操作&#xff1b; 3、外部函数添加成功后&#xff0c;其他程序文件均可使用该外部函数。

自定义prometheus监控获取nginx_upstream指标

1、前言 上篇文章介绍了nginx通过nginx_upstream_check_module模块实现后端健康检查&#xff0c;这篇介绍一下如何自定义prometheus监控获取nginx的upstream指标来实时监控nginx。 2、nginx_upstream_status状态 支持以下三种方式查看nginx_upstream的状态 /status?formatht…

【C++】标准库:介绍string类

string 一.string类介绍二.string类的静态成员变量三.string类的常用接口1.构造函数&#xff08;constructor&#xff09;2.析构函数&#xff08;destructor&#xff09;3.运算符重载&#xff08;operator&#xff09;1.operator2.operator[]3.operator4.operator 4.string的四…

Kitti数据集解析

目录 一、概述 2、详细内容 1、lable标签 2、标定参数 3、点云数据 C++代码读取bin文件 python代码读取bin文件 三、功能实现 1、点云数据转成投影到图像 2、图像数据转成投影到点云 3、点云3D结果转成图像BEV鸟瞰图结果 一、概述 KITTI整个数据集是在德国卡尔斯鲁厄…

DDoS攻击:威胁与防护策略

DDoS&#xff08;分布式拒绝服务&#xff09;攻击是网络安全领域的一大挑战&#xff0c;对企业造成严重的影响。本文将深入探讨DDoS攻击的原理和防护方法。 DDoS攻击的原理 DDoS攻击通过大量请求&#xff0c;使目标系统无法响应正常请求。攻击者利用多台计算机发送大量请求&am…

【Unity2D 2022:Data】读取csv格式文件的数据

一、创建csv文件 1. 打开Excel&#xff0c;创建xlsx格式文件 2. 编辑卡牌数据&#xff1a;这里共写了两类卡牌&#xff0c;第一类是灵物卡&#xff0c;具有编号、卡名、生命、攻击四个属性&#xff1b;第二类是法术卡&#xff0c;具有编号、卡名、效果三个属性。每类卡的第一…

使用在UE5中使用AirSim插件Eigen库头文件引用报错,出现报错的解决方式

一、概述 如图所示&#xff0c;用红线圈出的两条头文件引用会报错&#xff0c;提示无法找到他们&#xff0c;但是可以发现的是&#xff0c;他们的路径书写是没有问题的。 // #include <Source/Airlib/deps/eigen3/Eigen/Core> // #include <Source/Airlib/deps/eigen…

追问试面试系列:开篇

我们不管做任何事情&#xff0c;都是需要个理由&#xff0c;而不是盲目去做。 为什么写这个专栏&#xff1f; 就像我们被面试八股文时&#xff0c;市面上有很多面试八股文&#xff0c;随便一个八股文都是500&#xff0c;甚至1000面试题。诸多面试题&#xff0c;难道我们需要一…

【系统架构设计师】十八、信息系统架构设计理论与实践①

目录 一、信息系统架构概述 二、信息系统架构风格与分类 2.1 信息系统架构风格 2.2 信息系统架构分类 三、信息系统架构模型 3.1 单体应用 3.2 客户机/服务器 3.2.1 二层 C/S 3.2.2 三层 C/S 和 B/S 3.2.3 多层 C/S 和 B/S 3.2.4 MVC 3.3 面向服务架构(SOA)模式 …

PVE环境中调整虚拟机磁盘大小

我的希望将PVE中的虚拟机磁盘调整一下&#xff0c;增加20GB。在查询了一些资料后&#xff0c;做一下总结教程。 环境是 PVE8.2.2 版本&#xff0c;虚拟机系统是centos7.9.2009-minimal&#xff0c; 安装系统时划分磁盘分区方式是默认分区方式&#xff08;不同分区方式下&#…

RISC-V (二)汇编语言编程

简介 汇编语言是一种“低级”语言。 汇编语言的缺点&#xff1a; -难度 -难写 -难移植 汇编语言的优点&#xff1a; -灵活 -强大 汇编语言的应用场景 -需要直接访问底层硬件的地方 -需要对性能执行极致优化的地方 汇编语言语法介绍&#xff08;GNU版本&#xff09; 基本组成 …

《python程序语言设计》第6章15题财务应用程序:打印税款表。利用程序清单4-7的代码

6.15 打印税款表 def computeTax(status_n, income):tax 0if status_n 0:if income < 8350:tax income * 0.10elif income < 33950:tax 8350 * 0.10 (income - 8350) * 0.15elif income < 82250:tax 8350 * 0.10 (33950 - 8350) * 0.15 (income - 33950) * 0.…

Docker 制作java8镜像

一、在Linux服务器安装Docker 可参考&#xff1a;Linux安装Docker-CSDN博客 二、使用Dokcer制作java8镜像 2.1 上传jdk8的压缩包 mkdir -p /home/data/develop/jdk cd /home/data/develop/jdk 在该路径下上传jdk-8u261-linux-x64.tar.gz包 如下图&#xff1a; 2.2 编写Docke…

HALCON如何创建本地函数

HALCON中有本地函数(.hdev)、外部函数(HDevelop函数文件.hdvp)和库函数(.hdpl) 本地函数(.hdev)&#xff1a;创建后仅在当前程序文件中使用&#xff1b; 外部函数(HDevelop函数文件.hdvp)&#xff1a;创建后可以在其他程序文件中复用&#xff0c;默认保存在…/ procedures/下…

【React】详解 Redux 状态管理

文章目录 一、Redux 的基本概念1. 什么是 Redux&#xff1f;2. Redux 的三大原则 二、Redux 的核心组件1. Store2. Action3. Reducer 三、Redux 的使用流程1. 安装 Redux 及其 React 绑定2. 创建 Action3. 创建 Reducer4. 创建 Store5. 在 React 应用中使用 Store6. 连接 React…

【Java算法专场】二分查找(下)

目录 山脉数组的峰顶索引 算法分析 算法步骤 算法代码 算法示例 寻找峰值 算法分析 算法步骤 算法代码 算法示例 寻找旋转排序数组中的最小值 算法分析 算法步骤 算法代码 算法示例 点名 算法分析 算法步骤 算法代码 算法示例 山脉数组的峰顶索引 …