Spring Boot自动配置原理

小林 coding

Spring Boot的自动配置就是自动帮你把代码(依赖)变成对象(Bean)。

Spring Boot自动配置原理

我直接用一个真实的例子带你一步步看Spring Boot的自动配置是怎么工作的!

场景重现:你要创建一个Web项目

第一步:创建项目

xml 复制代码
<!-- pom.xml -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

第二步:启动类

java 复制代码
@SpringBootApplication  // 🔑 关键魔法开始的地方!
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

🧭 自动配置执行流程详解

阶段1:启动扫描

当你运行 SpringApplication.run() 时:

java 复制代码
// SpringBoot内部代码(简化版)
public class SpringApplication {
    public static void run(Class<?> primarySource, String... args) {
        // 1. 创建应用上下文
        ApplicationContext context = createApplicationContext();
        
        // 2. 加载配置类
        load(context, primarySource);
        
        // 3. 🔍 关键步骤:调用@SpringBootApplication注解的组件
    }
}

阶段2:解析@SpringBootApplication

java 复制代码
// @SpringBootApplication 内部结构
@SpringBootConfiguration      // 告诉Spring:这是配置类
@EnableAutoConfiguration      // 🔑 启动自动配置的关键!
@ComponentScan               // 扫描当前包下的组件
public @interface SpringBootApplication {
    // 这就是那个神奇的注解
}

阶段3:@EnableAutoConfiguration 的魔法

java 复制代码
// @EnableAutoConfiguration 的定义
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)  // 🔑 关键导入!
public @interface EnableAutoConfiguration {
    // 它导入了"自动配置选择器"
}

🔍 核心组件:AutoConfigurationImportSelector

AutoConfigurationImportSelector 是 Spring Boot 自动配置的核心,它主要做以下三件大事:

  1. 扫描并加载所有候选的自动配置类
    从哪里加载:从 classpath 下所有的 META-INF/spring.factories 文件(META-INF/spring.factories 文件是从依赖中来的。具体来说,它是打包在JAR文件中的)中加载 key 为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的配置类。

结果:得到一个包含所有自动配置类的列表(可能有100多个)。

  1. 过滤和去重
    根据条件注解过滤:根据类路径下的依赖(即有哪些类存在)、配置文件中的设置以及当前容器的状态(例如已有哪些Bean)来过滤掉不需要的自动配置类。

去重:确保相同的配置类不会重复加载。

排序:按照一定的顺序(例如使用 @AutoConfigureAfter、@AutoConfigureBefore 等注解定义的顺序)对自动配置类进行排序。

  1. 返回最终需要生效的自动配置类
    将过滤和排序后的自动配置类列表返回给 Spring 容器,Spring 容器会将这些类注册为 Bean 定义,随后实例化并配置相应的 Bean。

详细过程:

扫描 spring.factories 文件:

Spring Boot 在启动时会调用 AutoConfigurationImportSelector 的 selectImports 方法。

该方法内部会使用 SpringFactoriesLoader 工具类,从 classpath 中搜索所有 META-INF/spring.factories 配置文件,并读取其中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置类列表。

条件过滤:

加载的配置类并不是全部都会生效,每个自动配置类上都有很多条件注解(如 @ConditionalOnClass、@ConditionalOnBean、@ConditionalOnProperty 等)。

Spring Boot 会利用条件注解进行过滤,只有满足所有条件的自动配置类才会被最终使用。

去重和排序:

去除重复的配置类(可能多个 jar 包都提供了相同的自动配置类)。

按照一定的顺序排序,确保配置的加载顺序符合要求。

返回数组:

最终返回一个字符串数组,里面是过滤后需要加载的自动配置类的全限定名。

示例代码片段(简化):

java

public class AutoConfigurationImportSelector implements DeferredImportSelector {

复制代码
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    // 1. 获取所有自动配置类(从spring.factories)
    List<String> configurations = getCandidateConfigurations();
    
    // 2. 去重
    configurations = removeDuplicates(configurations);
    
    // 3. 根据条件注解过滤
    configurations = filter(configurations, autoConfigurationMetadata);
    
    // 4. 排序
    configurations = sort(configurations);
    
    // 5. 返回数组
    return configurations.toArray(new String[0]);
}

}

比喻:

第一步:就像你去图书馆,按照索引(spring.factories)找到所有可能相关的书(自动配置类)。

第二步:你根据这些书的目录(条件注解)判断哪些书是你当前需要的(过滤)。

第三步:你把选中的书按照一定的顺序(排序)放好,然后借回家(加载到容器)。

通过这三步,Spring Boot 就能够智能地根据项目的依赖和配置,自动加载所需的配置类,从而完成自动配置。

这是自动配置的大脑,它做了三件大事:

1. 加载所有候选配置

java 复制代码
public class AutoConfigurationImportSelector {
    
    // 这个方法会被Spring调用
    public String[] selectImports(AnnotationMetadata metadata) {
        // 1. 从所有jar包中读取 META-INF/spring.factories 文件
        List<String> configurations = getCandidateConfigurations();
        
        // 2. 去重和过滤
        configurations = removeDuplicates(configurations);
        configurations = sort(configurations);
        
        // 3. 返回所有自动配置类的全限定名
        return configurations.toArray(new String[0]);
    }
    
    // 加载配置
    protected List<String> getCandidateConfigurations() {
        // 读取这个文件:META-INF/spring.factories
        List<String> configurations = 
            SpringFactoriesLoader.loadFactoryNames(
                EnableAutoConfiguration.class, 
                getBeanClassLoader()
            );
        return configurations;
    }
}

2. 读取配置文件

spring-boot-autoconfigure-2.7.0.jar 中:

复制代码
META-INF/spring.factories 文件内容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
... 共有100多个自动配置类!

🎯 条件判断:智能选择

Spring Boot不是把所有100多个配置都加载,而是智能筛选

以WebMvcAutoConfiguration为例

java 复制代码
@Configuration(proxyBeanMethods = false)
// 🔍 关键条件判断:
@ConditionalOnWebApplication(type = Type.SERVLET)  // 必须是Web应用
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)  // 用户没有自己配
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    
    // 只有满足上述所有条件,这个配置类才生效!
}

实际判断逻辑:

java 复制代码
// 伪代码:Spring Boot内部的条件判断
if (有Servlet相关类 in classpath && 
    是Web应用 && 
    用户没有自定义WebMvc配置) {
    // 加载WebMvcAutoConfiguration
    加载这个类并创建Bean();
}

🏗️ 自动创建Bean

自动配置类内部:

java 复制代码
@Configuration
public class WebMvcAutoConfiguration {
    
    // 1. 定义ViewResolver Bean
    @Bean
    @ConditionalOnMissingBean  // 如果用户没定义,我才创建
    public InternalResourceViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
    
    // 2. 定义MessageConverter Bean
    @Bean
    @ConditionalOnMissingBean
    public MappingJackson2HttpMessageConverter jacksonMessageConverter() {
        return new MappingJackson2HttpMessageConverter();
    }
    
    // 3. 配置静态资源
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
    }
}

📊 完整流程图

复制代码
1. 启动应用
    ↓
2. 扫描@SpringBootApplication
    ↓
3. 发现@EnableAutoConfiguration
    ↓
4. 加载AutoConfigurationImportSelector
    ↓
5. 读取所有META-INF/spring.factories文件
    ↓
6. 收集100+个自动配置类
    ↓
7. 过滤(基于条件注解)←---→ 条件评估
    ↓
8. 剩下20个符合条件的配置类
    ↓
9. 加载这些配置类
    ↓
10. 执行@Bean方法
    ↓
11. 创建Bean放入Spring容器
    ↓
12. 应用启动完成,可以直接使用!

🎪 形象比喻

Spring Boot自动配置就像一个"智能管家":

  1. 你: "我要做Web开发"(加spring-boot-starter-web依赖)
  2. 管家: 收到!检查一下...
    • ✅ 有Servlet.class在类路径(Web环境)
    • ✅ 有DispatcherServlet.class(Spring MVC)
    • ❌ 用户没有自定义Web配置
    • ✅ 当前是SERVLET类型Web应用
  3. 管家: 所有条件满足,开始工作!
    • 🏗️ 安装Tomcat服务器
    • 🏗️ 配置Spring MVC
    • 🏗️ 设置JSON转换器
    • 🏗️ 配置静态资源路径
  4. 你: "我还需要数据库"
  5. 管家: 检查...
    • ✅ 有DataSource.class(加了数据库驱动)
    • ✅ 有spring.datasource.url配置
    • ❌ 用户没有自定义DataSource
  6. 管家: 开始配置数据库!
    • 🏗️ 创建DataSource连接池
    • 🏗️ 配置连接参数
    • 🏗️ 设置事务管理器

🔧 源码跟踪示例

如果你想亲眼看看自动配置是怎么工作的,可以这样:

java 复制代码
// 1. 在application.properties中开启debug
debug=true

// 2. 启动应用,查看控制台日志
=========================
AUTO-CONFIGURATION REPORT
=========================

Positive matches:  // 匹配成功的
-----------------
   WebMvcAutoConfiguration matched:
      - @ConditionalOnClass found required classes 
        'javax.servlet.Servlet', 'org.springframework.web.servlet.DispatcherServlet'
      - found 'session' scope (OnWebApplicationCondition)
      
   DataSourceAutoConfiguration matched:
      - @ConditionalOnClass found required classes 
        'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType'
      - @ConditionalOnProperty (spring.datasource.type) matched

Negative matches:  // 匹配失败的
-----------------
   RabbitAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 
           'com.rabbitmq.client.ConnectionFactory'
           
   RedisAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 
           'org.springframework.data.redis.core.RedisOperations'

🎯 核心原理总结

Spring Boot自动配置的核心是:

  1. 通过依赖推断需求(看你classpath有什么)
  2. 通过条件注解智能判断(@ConditionalOnXxx)
  3. 按默认最佳实践创建Bean(遵循约定大于配置)
  4. 允许用户轻松覆盖(@Bean或配置文件)

💡 一句话理解

Spring Boot自动配置 = "条件装配" + "约定优先" + "零配置开箱即用"

它就像一个懂你的助手:

  • 看你带了什么工具(依赖)
  • 猜你要做什么事(条件判断)
  • 按最常用的方式帮你准备好(自动配置)
  • 但你随时可以自己动手(自定义配置)

这样既能让新手快速上手,又能让老手灵活定制!

相关推荐
寻星探路38 分钟前
Java EE初阶启程记15---文件操作和IO
java·java-ee
阿巳helloWorld39 分钟前
SpringMVC底层流程解析
java·开发语言
heartbeat..40 分钟前
介绍java中常用于处理 Excel 文件的Apache POI
java·apache·excel·poi
路边草随风40 分钟前
java 实现 flink 读 kafka 写 iceberg
java·flink·kafka
风象南41 分钟前
SpringBoot ThreadLocal 父子线程传值的几种实现方式
后端
路边草随风42 分钟前
java 实现 flink cdc 读 mysql binlog 按表写入kafka不同topic
java·大数据·mysql·flink
低客的黑调42 分钟前
Spring MVC 全面详解:原理、组件、实战与高级特性
java·spring·mvc
STARFALL00142 分钟前
spring mvc 自定义Converter 设置
java·spring·mvc
java_logo43 分钟前
Jenkins Docker 容器化部署指南
java·运维·servlet·docker·容器·jdk·jenkins