Spring Boot 原理篇
Spring系列框架是目前全世界最流行的java开发框架,可以说**Spring是现代java开发的基石**,它划分了多个子框架 ,如:SpringData,SpringBoot,SpringCloud,SpringAI,SpringFramework...其中SpringFramework是所有模块的基础。
分析Spring Boot原理可以使我们更好的熟练使用Spring Boot,并汲取其优秀的设计思想。
若直接使用SpringFramework,依赖配置将非常繁琐,每次引入一个依赖,都要找到其配套的所有依赖及其版本。基于此,Spring官方基于SpringFramework4.0之后版本 推出一个全新的框架SpringBoot,通过SpringBoot来简化 SpringFrmework的开发(注意是简化,不是替代,也就是说SpringBoot是SpringFramework的上层框架),而SpringBoot又是Spring家族中最流行的框架,Spring官方也推荐直接使用SpringBoot构建项目。
使用SpringBoot构建并开发项目会使项目开发更方便快捷,主要原因就是最核心的两个功能:起步依赖、自动配置 。解析SpringBoot的原理,就是来解析起步依赖和自动配置的原理
- 通过起步依赖 ,可以大大简化
pom.xml文件中依赖的配置 ,解决SpringFramework中依赖配置繁琐的问题。 - 通过自动配置 ,可以大大简化框架使用过程中
Bean的声明及配置。
注:下文核心细节的知识点用图标表示重要程度
-
⭐:核心,作为使用Sping Boot的上层开发者必须要掌握的
-
🍀:了解,不需要深入学习,了解即可,学习它可更好了解Spring Boot的底层设计与实现
起步依赖
我们只需引入起步依赖,常见的基本依赖都会随之引入。
在SpringBoot之前,光使用SpringFramework,项目开始需要引入很多基本依赖,非常地繁琐。

使用SpringBoot创建项目后,引入一个起步依赖(以Web开发为例:spring-boot-start-web)即可将许多基本依赖会随之引入:

原理也很简单,就是maven的依赖传递。所谓依赖传递指:若A依赖B,B依赖C,引入A依赖,B、C依赖也会随之引入。
自动配置
自动配置:当spring启动后,一些配置、bean对象(引入的依赖中存在)自动存入到IOC容器中,不需要我们手动声明,从而简化了开发,省去了繁琐的配置操作。
研究SpringBoot的自动配置,其实重点需要研究在Spring启动后
SpringBoot是如何将依赖jar包中的Bean对象 注入到IOC容器中的?- 它是如何识别依赖
jar包中哪些对象 是需要加载到IOC容器的成为Bean对象? - 加载
Bean对象的规则 是怎么样的?加载的流程又是怎么样的?
包扫描与导入
包扫描:Spring中,通过@Commonent注解及其衍生注解可以实现自定义Bean对象的定义,Spring启动时默认会扫描启动类所在包及其子包 中的所有类来实现寻找bean对象,并将其加载到IOC容器中。也可使用@ComponentScan添加参数实现自定义扫描范围,例如:
java
@ComponentScan({"com.example","com.gezishan","org.mybatis"})
@SpringBootApplication
public calss SpringbootWebApplication{
}
如果将依赖jar包中的Bean对象加载到IOC容器也使用这种方式 ,配置将非常繁琐,依赖多了,包扫描的范围也很大,但Bean对象并没有多少,这样效率就很低。
Spring也提供了另一种将Bean对象加载到IOC容器的方法,那就是导入。
导入:Spring中,通过@Import注解指定**Class参数**实现导入,使用@Import导入的类会被加载进IOC容器,导入类的类型有:
- 导入普通类,指定的该普通类 会被加载进
IOC容器 - 导入配置类,指定的配置类所配置的所有
Bean对象 会被加载进IOC容器 - 导入
ImportSlector接口实现类(下文称自动配置选择器),该实现类的slectImporte()方法返回的字符串类名数组对应的类 会被加载进IOC容器
java
//导入一个普通类和一个配置类以及ImportSlector接口实现类
@Import({TokenParser.class,HeaderConfig.class,MyImportSelector.class})
@SpringBootApplication
public calss SpringbootWebApplication{
}
⭐ImportSlector接口
翻看源码:

该接口有一个必须实现的方法slectImporte(),返回值是一个字符串数组 ,表示需要交给IOC容器管理的类名数组,可以将Bean对象的全类名封装成数组中返回。
配置管理:需要交出去的Bean对象很多时,可以写一份文件列出要交出去的Bean对象,再在slectImporte()方法中读取文件中所有的Bean对象全类名。这样配置管理就更加方便,代码也更清晰,不用在@Import中罗列那么多类名。
对于第三方的jar包中的Bean对象,通常由第三方的开发者自己定义导入。
🍀 @EnableXxxx注解
@EnableXxxx注解是一个泛称,它表示第三方提供的注解,通常封装了@Import注解
启动流程
⭐@springBootApplication
@springBootApplication注解是SpringBoot项目的核心注解,它标识在SpringBoot工程的启动类上,该注解由三部分组成:
@SpringBootConfiguration:该注解与@Configuration相同,用来声明当前类也是一个配置类。@ComponentScan:组件扫描,默认扫描当前启动类所在包及其子包 内的所有类文件,用于将自定义的Bean对象加载到IOC容器。@EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解 ,用于将依赖jar包中的Bean对象加载到IOC容器。
翻看源码:

⭐@EnableAutoConfiguration
@EnableAutoConfiguration 的作用是开启自动配置机制 ,是自动配置的核心,其实现依赖两个关键步骤
- @Import({AutoConfigurationImportSelector.class})
通过@import导入AutoConfigurationImportSelector类(自动配置选择器),它通过slectImporte()方法返回待加载的Bean对象类名数组
- 加载自动配置类的候选名单
AutoConfigurationImportSelector的slectImporte()方法的内部会执行以下步骤
- 读取
spring.factories文件:从所有类路径下的META-INF/spring.fectories文件中加载要自动配置的类。
以MyBatisPlus 的spring.factories文件为例:

- 筛选有效的自动配置类:通过条件装配注解(@ConditionalXxxx系列注解)和AutoConfigurationMetadata
⭐类路径ClassPath
类路径(ClassPath) 指的是 Java 程序运行时,JVM 用于查找类(.class字节码文件)、资源(如配置文件、图片等)的路径。这些路径在编译、打包和运行时会被 JVM 识别并加载。
开发阶段(IDE 中)
在 Maven 或 Gradle 项目的标准目录结构中,类路径对应:
-
src/main/java:存放 Java 源代码,编译后的.class文件会被输出到target/classes(Maven)或build/classes(Gradle)。 -
src/main/resources:存放资源文件(如application.properties、META-INF/spring.factories等),这些文件会被直接复制到target/classes或build/classes,成为类路径的一部分。例如,若在
src/main/resources/META-INF/下创建spring.factories,编译后会被放入target/classes/META-INF/spring.factories,此时该文件处于类路径中,可被 Spring Boot 扫描到。
打包后(Jar/War 包中)
当项目打包为 Jar 或 War 包后,类路径对应包内的根目录:
- Jar 包中,
META-INF/spring.factories通常位于 Jar 包的根目录下的META-INF文件夹中(如xxx.jar!/META-INF/spring.factories)。
例如,Spring Boot 内置的 spring-boot-autoconfigure.jar 中就包含 META-INF/spring.factories,定义了默认的自动配置类列表。
依赖包中的类路径
jar包中依赖的jar包会通过依赖传递,也成为项目的类路径。
Spring Boot 在启动时会扫描所有依赖 jar 包 及当前项目自身类路径下 的spring.factories文件,汇总其中的配置信息。
⭐ @ConditionalXxxx系列注解
自动配置类并非在候选名单中就无条件生效 ,它可通过注解实现动态装配,满足条件才会被注册为Bean对象。
@Conditional注解是条件装配注解,作用是按照一定的条件进行判断,在满足给定条件后才会注册对应的Bean对象到IOC容器中。
使用位置:方法、类
@Conditional本身是一个父注解,它派生出大量的子注解用于具体的条件判断,以下是常用的几个:
| 注解 | 作用 |
|---|---|
| @ConditionalOnClass | 类路径中存在指定类时生效 |
| @ConditionalOnMissingClass | 类路径中不存在指定类时生效 |
| @ConditionalOnBean | 容器中存在指定 Bean 时生效 |
| @ConditionalOnMissingBean | 容器中不存在指定 Bean 时生效 |
| @ConditionalOnProperty | 配置文件中存在指定属性且值匹配时生效 |
| @ConditionalOnWebApplication | 应用是 Web 应用时生效 |
| @ConditionalOnNotWebApplication | 应用不是 Web 应用时生效 |
@ConditionalOnClass:判断环境中有对应字节码文件,才注册bean到IOC容器。
java
@Configuration
public class HeaderConfig{
@Bean
@ConditionalOnClass(name = "io.jsonwebtoken.Jwts") //判断环境中存在Jwts类才会注册此Bean对象
public HeaderParser headerParser(){
return new HeaderParser();
}
}
@ConditionalOnMissingBean:判断环境中没有对应dean(可根据类型或名称判断),才注册bean到IOC容器。
java
@Configuration
public class HeaderConfig{
@Bean
@ConditionalOnMissingBean //判断环境中不存在此类型的Bean,才会注册此Bean对象。也可指定类型(使用注解的value属性)或名称(使用注解的name属性)判断
public HeaderParser headerParser(){
return new HeaderParser();
}
}
@ConditionalOnProperty:判断application配置文件中有对应属性和值,才注册bean到IOC容器。
java
@Configuration
public class HeaderConfig{
@Bean
@ConditionalOnProperty(name="name",havingValue="gezishan") //判断配置文件中存在属性为"name",属性值为"gezishan"的配置项,才会注册此Bean对象
public HeaderParser headerParser(){
return new HeaderParser();
}
}
除此之外还有许多派生注解:

🍀 AutoConfigurationMetadata
核心作用
AutoConfigurationMetadata 是 Spring Boot 自动配置过程中用于存储和提供自动配置类条件信息 的元数据容器,它的核心作用是优化自动配置类的条件判断效率,避免在类路径扫描和条件校验时进行不必要的类加载或反射操作。
在 Spring Boot 自动配置中,大量自动配置类(如 WebMvcAutoConfiguration、DataSourceAutoConfiguration 等)通过 @ConditionalXxxx 系列注解(如 @ConditionalOnClass、@ConditionalOnMissingClass)控制是否生效。这些条件判断通常需要检查类路径中是否存在某个类 ,或某个类是否有特定方法等。
如果每次直接通过反射或类加载器实时检查,会有两个问题:
- 性能开销:频繁的类加载和反射操作会降低启动速度。
- 潜在冲突:某些类可能在检查时被提前加载,导致后续逻辑异常。
数据来源
AutoConfigurationMetadata 的出现就是为了预先生成并缓存这些条件判断所需的元数据,在自动配置阶段直接读取元数据,避免实时检查,提升效率。
AutoConfigurationMetadata 的元数据来自于编译期生成的 META-INF/spring-autoconfigure-metadata.properties 文件。
这个文件由 Spring Boot 提供的 spring-boot-autoconfigure-processor 注解处理器在项目编译时自动生成 ,内容是对所有自动配置类的条件注解信息的预处理结果。
例如,对于注解了 @ConditionalOnClass({DataSource.class}) 的 DataSourceAutoConfiguration,编译后会在 spring-autoconfigure-metadata.properties 中生成类似如下的条目:
properties
# 格式:自动配置类全类名.条件类型=值
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration.ConditionalOnClass=javax.sql.DataSource
核心步骤
-
快速条件校验
在
AutoConfigurationImportSelector筛选自动配置类时,会先通过AutoConfigurationMetadata读取预存的条件信息(如需要检查的类名),而非直接加载类。只有元数据指示 "可能符合条件" 时,才会进一步通过类加载器验证,减少不必要的类加载。 -
缓存元数据
AutoConfigurationMetadata会将spring-autoconfigure-metadata.properties中的内容加载到内存中,形成键值对缓存,供自动配置过程中快速查询。 -
支持多种条件类型
除了
@ConditionalOnClass,它还能处理@ConditionalOnMissingClass、@ConditionalOnResource等注解的元数据,例如:properties# 检查是否缺少某个类 org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.ConditionalOnMissingClass=org.springframework.web.reactive.DispatcherHandler # 检查是否存在某个资源 org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.ConditionalOnResource=classpath:org/hibernate/cache/ spi/RegionFactory.class
使用场景
作为开发者,我们通常不需要直接操作 AutoConfigurationMetadata,但了解它的存在有助于理解自动配置的效率优化机制。
- 当自定义自动配置类时,只要在项目中引入
spring-boot-autoconfigure-processor依赖(通常已包含在spring-boot-starter中),编译时就会自动生成元数据文件,无需手动干预。 - 若需排查自动配置类未生效的原因,可查看
spring-autoconfigure-metadata.properties中的元数据,确认条件判断的预期值是否与实际环境一致。
⭐个性化配置
配置绑定 @ConfigurationProperties
自动配置类通常会通过 @ConfigurationProperties 注解,将配置文件(如 application.yaml)中的属性与 Java 类绑定,实现配置的动态注入。
示例 :DataSourceProperties 绑定数据库配置:
java
@ConfigurationProperties(prefix = "spring.datasource") // 绑定前缀为spring.datasource的配置
public class DataSourceProperties {
private String url;
private String username;
private String password;
// getters/setters
}
配置文件 application.properties 中可直接设置:
yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
自动配置的优先级:用户配置 > 自动配置
SpringBoot 遵循用户配置优先于自动配置 的原则(个性先于全局):
- 若用户手动定义了某个 Bean(如
@Bean注解),则自动配置类中通过@ConditionalOnMissingBean标注的同名 Bean 会被忽略。 - 例如:用户自定义了
DataSource类型的 Bean,则DataSourceAutoConfiguration中自动配置的数据源会失效。
Starter规范
Spring项目中的Starter就是前面讲得起步依赖。
SpringBoot有自带的Starter,如:spring-boot-starter-web、spring-boot-starter-aop等(一般规范:模块名在后)。- 很多第三方库也有对应的
SpringBoot的Starter,如:mybatis-spring-boot-starter,pagehelper-spring-boot-starter等(一般规范:模块名在前)。
Starter一般用于实现自动装配的配置,通过Starter可实现快速适配 Spring项目,当然,也有不少第三方库没有Starter,我们可以通过自己写Starter来实现对第三方库中的一些对象工具进行Bean声明等配置,以实现快速适配Spring项目,并实现组件化复用 。在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。在SpringBoot项目中,一般会将这些组件封装为Starter。
一般Starter中需要引入一份spring-boot-autoconfigure依赖以实现对Bean对象的自动配置:

我们先来分析一下mybatis-spring-boot-starter依赖的jar包:

目录结构如上图所示,mybatis的starter依赖jar包中没有一行代码,其中有一些配置文件,其pow.xml文件引入了很多有关mybatis操作的依赖:

包括:
- 起步依赖
spring-boot-starter,使用spring提供的注解@Bean、@Configurition及其他基本功能实现对mybatis的Bean的配置等。 - 起步依赖
spring-boot-starter-jdbc,使用spring-boot封装的jdbc功能,实现对数据库的操作 mybatis依赖,实现mybatis的核心功能mybatis-spring依赖,基于spring的mybatis的功能mybatis-spring-boot-autoconfigure,实现spring自动装配的核心配置