乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Spring Boot 概述

    • 章节导读:Spring Boot概述与核心理念
    • Spring Boot是什么
    • Spring Boot与Spring Framework的关系
    • 约定优于配置
  • 第2章 快速入门与第一个应用

    • 章节导读:快速入门与第一个应用
    • SpringApplication
    • 第一个Spring Boot应用
  • 第3章 起步依赖与版本管理

    • 章节导读:起步依赖与版本管理
    • 起步依赖
    • BOM版本管理
  • 第4章 自动配置原理

    • 章节导读:自动配置原理
    • 自动配置原理
    • AutoConfigurationImportSelector
    • 自动配置报告
  • 第5章 核心注解

    • 章节导读:核心注解
    • @SpringBootApplication
    • @EnableAutoConfiguration
    • @ConditionalOnClass
    • @ConditionalOnMissingBean
    • @ConditionalOnBean
    • @ConditionalOnProperty
  • 第6章 外部化配置与属性绑定

    • 章节导读:外部化配置与属性绑定
    • 外部化配置
    • @ConfigurationProperties
    • @Value
    • 配置属性优先级
  • 第7章 Profile 与环境切换

    • 章节导读:Profile与环境切换
    • @Profile
    • 多环境配置文件
  • 第8章 内嵌服务器与部署

    • 章节导读:内嵌服务器与部署
    • 内嵌服务器
    • Fat Jar
  • 第9章 Actuator 与监控

    • 章节导读:Actuator与监控
    • Actuator Health
    • Actuator Info
    • Actuator Metrics
    • 自定义Endpoint
    • 自定义HealthIndicator
  • 第10章 开发工具与最佳实践

    • 章节导读:开发工具与最佳实践
    • Banner自定义
    • 热部署

一句话定位:Spring Boot 的自动配置是"基于条件评估的按需 Bean 注册机制"——从 @EnableAutoConfiguration 触发 AutoConfigurationImportSelector 读取 spring.factories,经过逐层条件注解过滤,最终将满足类路径、容器状态和配置属性三重条件的候选配置类注册为可用 Bean。


定义与作用

Spring Boot 自动配置(Auto-configuration)是其最核心的特性。它解决的根本痛点是:传统 Spring 项目需要开发者手动编写大量基础设施配置(数据源、事务、Web 服务器等),而 Spring Boot 根据类路径中的依赖、已有的 Bean 定义和外部配置属性,自动装配一套可用的应用基础设施。

对比传统 SSM 与 Spring Boot:

配置项传统 SSM 手动配置Spring Boot 自动配置
数据源手写 DataSource Bean,配置 driver、url、username、password检测到 spring-jdbc + HikariCP 后自动配置
事务管理器手动声明 PlatformTransactionManager自动配置 DataSourceTransactionManager
Web 服务器外部部署 WAR 到 Tomcat检测到 spring-web 后自动内嵌 Tomcat
Jackson JSON手动配置 ObjectMapper自动配置,开箱即用
日志框架手动配置 logback.xml自动配置 SLF4J + Logback

在 Spring Boot 2.7.x 中,自动配置的核心入口是 @EnableAutoConfiguration,它通过 @Import(AutoConfigurationImportSelector.class) 触发整个自动配置流程(详见Spring Core的IoC容器负责Bean实例化流程)。


适用位置与常用属性

自动配置的触发位置

自动配置不是由开发者直接"使用"的,而是在启动时自动触发。开发者唯一需要做的是在启动类上标注 @SpringBootApplication(或 @EnableAutoConfiguration):

package com.feixiang.student;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

开发者可影响的配置属性

虽然自动配置是自动的,但开发者可以通过以下方式控制它:

方式说明示例
exclude排除特定自动配置类@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
spring.autoconfigure.exclude通过配置属性排除spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
debug=true输出条件评估报告查看哪些自动配置生效/被跳过
application.yml覆盖自动配置的属性spring.datasource.url=jdbc:mysql://...

核心原理

自动配置完整流程

从 spring.factories 到 Bean 注册的层次图

关键理解:自动配置的本质是条件化配置(Conditional Configuration)。Spring Boot 在启动时并非"一股脑加载所有配置",而是像安检通道一样,让每个候选配置类通过层层条件检查——只有全部通过,才会被注册为 Bean。这保证了"按需加载",避免引入不必要的 Bean 和配置。


完整示例

场景简述

飞翔科技(广州)的学生成绩管理系统 com.feixiang.student 正在从 Spring Framework 5.x 手动配置迁移到 Spring Boot 2.7.18。架构师白歌要求后端开发小崔理解:当运行 SpringApplication.run() 时,Spring Boot 到底做了哪些自动配置决策?为什么引入 spring-boot-starter-web 后 Tomcat 自动启动了?为什么引入 spring-boot-starter-jdbc 后数据源自动配置了?

小崔需要跟踪一次完整的启动流程,看清自动配置的每个决策点。

操作前:传统 Spring 手动配置

// 操作前:错误示范(传统 Spring 方式)
package com.feixiang.student;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.feixiang.student")
@EnableWebMvc
public class StudentManagementConfig {
    
    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/student_db");
        ds.setUsername("root");
        ds.setPassword("secret");
        return ds;
    }
    
    // 还需要手动配置:TransactionManager、JdbcTemplate、ViewResolver、Jackson...
    //  dozens more...
}

问题:

  1. 每个新项目都要复制粘贴这套配置
  2. 依赖版本(如 HikariCP、Jackson)需要手动管理,容易冲突
  3. 没有统一的条件判断逻辑——如果去掉某个依赖,配置类可能编译报错或运行报错

使用该特性的完整代码

小崔将项目迁移到 Spring Boot 2.7.18,使用自动配置:

pom.xml:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

application.yml:

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/student_db
    username: root
    password: secret
    driver-class-name: com.mysql.cj.jdbc.Driver

debug: true

启动类:

package com.feixiang.student;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

业务代码(无需任何配置):

package com.feixiang.student.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class StudentService {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public String queryScore(Long studentId) {
        // 自动配置已注册 JdbcTemplate,直接注入使用
        return "查询学生 " + studentId + " 的成绩";
    }
}

操作后运行结果及分析

开启 debug: true 后,启动日志中的自动配置报告(关键片段):

=========================
AUTO-CONFIGURATION REPORT
=========================

Positive Matches:
-----------------

   DataSourceAutoConfiguration
      - @ConditionalOnClass found required classes 'javax.sql.DataSource', 'com.zaxxer.hikari.HikariDataSource' (OnClassCondition)
      - @ConditionalOnMissingBean (types: javax.sql.DataSource; SearchStrategy: all) did not find any beans (OnBeanCondition)
      - @ConditionalOnProperty (spring.datasource.url) matched (OnPropertyCondition)

   HibernateJpaAutoConfiguration
      - @ConditionalOnClass found required class 'javax.persistence.EntityManager' (OnClassCondition)
      - @ConditionalOnMissingBean (types: javax.sql.DataSource; SearchStrategy: all) found: dataSource (OnBeanCondition)
      - @ConditionalOnProperty (spring.jpa.hibernate.ddl-auto) did not match (OnPropertyCondition)
      - Did not match: @ConditionalOnProperty did not find property 'spring.jpa.hibernate.ddl-auto' (OnPropertyCondition)

   WebMvcAutoConfiguration
      - @ConditionalOnClass found required classes 'javax.servlet.Servlet', 'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition)
      - @ConditionalOnWebApplication (required) found 'session' scope (OnWebApplicationCondition)
      - @ConditionalOnMissingBean (types: org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; SearchStrategy: all) did not find any beans (OnBeanCondition)

   JacksonAutoConfiguration
      - @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper' (OnClassCondition)
      - @ConditionalOnMissingBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) did not find any beans (OnBeanCondition)

   JdbcTemplateAutoConfiguration
      - @ConditionalOnClass found required classes 'org.springframework.jdbc.core.JdbcTemplate', 'javax.sql.DataSource' (OnClassCondition)
      - @ConditionalOnSingleCandidate (types: javax.sql.DataSource; SearchStrategy: all) found: dataSource (OnBeanCondition)

Negative Matches:
-----------------

   MongoAutoConfiguration
      - @ConditionalOnClass did not find required class 'com.mongodb.client.MongoClient' (OnClassCondition)

   RabbitAutoConfiguration
      - @ConditionalOnClass did not find required class 'com.rabbitmq.client.Channel' (OnClassCondition)

   RedisAutoConfiguration
      - @ConditionalOnClass did not find required class 'org.springframework.data.redis.core.RedisOperations' (OnClassCondition)

分析:

  1. DataSourceAutoConfiguration 正匹配:

    • @ConditionalOnClass:javax.sql.DataSource 和 HikariDataSource 均在类路径中(spring-boot-starter-jdbc 引入)
    • @ConditionalOnMissingBean:容器中没有用户自定义的 DataSource
    • @ConditionalOnProperty:spring.datasource.url 已配置 → 自动创建 HikariCP 连接池
  2. HibernateJpaAutoConfiguration 负匹配:

    • @ConditionalOnClass 通过:javax.persistence.EntityManager 存在
    • @ConditionalOnBean 通过:容器中有 dataSource(@ConditionalOnSingleCandidate 检测到单一候选)
    • @ConditionalOnProperty 失败:缺少 spring.jpa.hibernate.ddl-auto → 因为小崔没有引入 spring-boot-starter-data-jpa,所以 JPA 自动配置被跳过。这是正确的行为。
  3. WebMvcAutoConfiguration 正匹配:

    • @ConditionalOnClass:Servlet 和 DispatcherServlet 存在(spring-boot-starter-web 引入)
    • @ConditionalOnWebApplication:当前是 Web 应用(有 session scope)
    • @ConditionalOnMissingBean:没有 WebMvcConfigurationSupport → 自动配置 Spring MVC 和嵌入式 Tomcat
  4. JacksonAutoConfiguration 正匹配:ObjectMapper 类存在,且容器中没有用户自定义的 → 自动配置 JSON 序列化

  5. JdbcTemplateAutoConfiguration 正匹配:JdbcTemplate 和 DataSource 类存在,且容器中有 DataSource Bean(@ConditionalOnSingleCandidate)→ 自动注册 JdbcTemplate

  6. MongoAutoConfiguration、RabbitAutoConfiguration、RedisAutoConfiguration 负匹配:相关类不在类路径中 → 正常跳过


易错场景与面试考点

易错场景一:误以为自动配置是"魔法",不理解条件链

// 错误示范:小崔以为自动配置会无条件加载所有配置
package com.feixiang.student;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StudentManagementApplication {
    public static void main(String[] args) {
        // 小崔困惑:为什么我引入了 spring-boot-starter-data-redis,
        // 但 Redis 没有自动配置?
        SpringApplication.run(StudentManagementApplication.class, args);
    }
}

排查:小崔通过 debug=true 发现:

RedisAutoConfiguration:
  Did not match:
     - @ConditionalOnProperty (spring.redis.host) did not find property 'host' (OnPropertyCondition)

原来小崔没有在 application.yml 中配置 spring.redis.host!RedisAutoConfiguration 虽然通过了 @ConditionalOnClass,但内部某些条件要求 spring.redis.host 或相关属性存在。小崔以为"引入依赖就自动生效",忽略了配置属性的作用。

正确理解:自动配置是多条件链决策,不是"有依赖就生效"。每个自动配置类可能同时受 @ConditionalOnClass、@ConditionalOnProperty、@ConditionalOnMissingBean 等多重约束。排查时应使用 debug=true 逐级分析。

易错场景二:自定义 Bean 与自动配置 Bean 类型冲突

// 错误示范:自定义 Bean 与自动配置默认 Bean 同名但不同实现
package com.feixiang.student.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
public class JacksonConfig {
    
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        // 自定义序列化规则...
        return mapper;
    }
}

后果:JacksonAutoConfiguration 上有 @ConditionalOnMissingBean(ObjectMapper.class)。当 JacksonConfig 被扫描后,容器中已有 ObjectMapper Bean。JacksonAutoConfiguration 被跳过,不会注册默认的 ObjectMapper。这本身没问题——用户的自定义实现生效了。但如果小崔期望的是"自定义配置 + 自动配置的组合"(如保留默认 ObjectMapper 但增加模块),这种直接覆盖的方式会导致自动配置的所有附加功能(如 JavaTimeModule 注册)全部丢失。

正确做法:

  1. 如果只是微调,使用 ObjectMapperCustomizer(Spring Boot 提供的扩展点):
@Bean
public ObjectMapperCustomizer customizer() {
    return mapper -> mapper.registerModule(new JavaTimeModule());
}
  1. 如果确实需要完全自定义,确保理解自动配置被跳过的后果,并手动补齐所有需要的配置。

面试考点

Q:Spring Boot 自动配置的原理是什么?

核心流程:@SpringBootApplication → @EnableAutoConfiguration → @Import(AutoConfigurationImportSelector.class) → SpringFactoriesLoader 读取 spring.factories 中的候选配置类列表 → AutoConfigurationImportSelector 执行去重、排除和条件过滤 → ConditionEvaluator 逐个评估 @ConditionalOnClass、@ConditionalOnMissingBean、@ConditionalOnProperty 等条件注解 → 正匹配的配置类被注册为 BeanDefinition,负匹配的被跳过。AutoConfigurationImportSelector 实现 DeferredImportSelector,确保自动配置在用户配置之后处理,实现"用户自定义优先"。

Q:为什么 Spring Boot 能实现"零配置"启动?

"零配置"是相对的,并非真的没有配置,而是配置被自动化了。Spring Boot 通过 Starter 引入依赖,通过 spring.factories 注册候选配置类,通过条件注解筛选出满足当前环境的配置,通过外部化配置(application.yml)注入参数。开发者只需写业务代码和少量环境相关配置,基础设施配置由自动配置完成。

Q:@ConditionalOnMissingBean 和 @ConditionalOnBean 在自动配置中分别扮演什么角色?

@ConditionalOnMissingBean 是"用户优先守卫":它确保自动配置只在用户没有自定义同类 Bean 时才创建默认实现。这是"约定优于配置,配置优于硬编码"哲学的核心体现。@ConditionalOnBean 是"依赖链连接器":它确保当前自动配置类只在依赖的前置 Bean 已注册时才生效,用于构建自动配置类之间的有序依赖关系。

Q:Spring Boot 2.7 的 AutoConfiguration.imports 文件相比传统的 spring.factories 有什么优势?

  1. 文件职责分离:AutoConfiguration.imports 只放自动配置类,spring.factories 可以放其他 SPI 扩展;2. 每行一个类名,不再需要逗号分隔,可读性和可维护性更好;3. 避免 spring.factories 中 key=value 格式可能导致的拼写错误;4. Spring Boot 3.x 中完全移除了 spring.factories 对自动配置的支持,2.7 是过渡版本。两种写法在 2.7.x 中均兼容,但官方推荐新文件。

Q:自动配置报告中的 Positive Match 和 Negative Match 对排查问题有什么帮助?

Positive Match 告诉我们哪些自动配置生效了,确认基础设施(如数据源、Web 服务器)是否按预期加载;Negative Match 告诉我们哪些自动配置被跳过了以及原因——@ConditionalOnClass 失败说明缺少依赖,@ConditionalOnProperty 失败说明配置属性缺失或值不匹配,@ConditionalOnMissingBean 失败说明用户自定义了同类 Bean。这是定位"为什么某个功能没生效"的最直接证据。

上一页
章节导读:自动配置原理
下一页
AutoConfigurationImportSelector