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

    • 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自定义
    • 热部署

一句话定位:AutoConfigurationImportSelector 是 Spring Boot 自动配置的配置读取器与调度中枢,它负责从 spring.factories 加载候选自动配置类列表,执行去重、排除和条件评估,最终决定哪些配置类应该被注册进 Spring 容器。


定义与作用

AutoConfigurationImportSelector 实现了 ImportSelector 接口(以及 DeferredImportSelector),是 @EnableAutoConfiguration 通过 @Import 引入的核心处理类。它的职责可以用三个字概括:读、滤、报。

阶段职责输出
读读取 spring.factories 中所有 EnableAutoConfiguration 对应的配置类候选配置类列表(约 200+ 个)
滤去重、应用 exclude 排除、过滤已处理的配置类精简后的配置类列表
报将每个配置类的条件评估结果写入 AutoConfigurationReportdebug=true 时可查看的正/负匹配报告

对比传统 Spring:没有这个类的时代

在传统 Spring Framework 中,开发者需要在 applicationContext.xml 中手动声明所有基础设施 Bean:

<!-- 传统 SSM 的繁琐配置 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/student_db"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<!--  dozens more... -->

AutoConfigurationImportSelector 让这一切自动化:它扫描类路径,找到所有候选配置类,只把满足条件的注册进来,将开发者从重复配置中解放。


适用位置与常用属性

适用位置

AutoConfigurationImportSelector 不是开发者直接使用的注解,它是一个 Spring Boot 内部类。开发者唯一与它交互的方式是 @EnableAutoConfiguration(或 @SpringBootApplication)隐式触发它。

// AutoConfigurationImportSelector 的触发方式(开发者视角)
@SpringBootApplication  // ← 内部包含 @EnableAutoConfiguration
public class StudentManagementApplication { ... }

// 等价于:
@EnableAutoConfiguration  // ← 内部包含 @Import(AutoConfigurationImportSelector.class)
public class StudentManagementApplication { ... }

开发者可扩展点

虽然不需要直接使用 AutoConfigurationImportSelector,但开发者可以通过以下方式影响它的行为:

扩展点说明示例
spring.factories注册自定义自动配置类com.feixiang.student.config.StudentCacheAutoConfiguration
exclude排除官方自动配置类@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
spring.autoconfigure.exclude通过配置属性排除spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

核心原理

类结构与核心方法

完整处理流程

关键理解:

  1. 延迟导入:AutoConfigurationImportSelector 实现 DeferredImportSelector,意味着它在所有普通 @Configuration 类处理完毕后才执行。这确保了用户自定义的 Bean 先于自动配置类被注册,为 @ConditionalOnMissingBean 判断提供正确的容器状态。

  2. 条件过滤分层:AutoConfigurationImportFilter 在正式注册前进行一轮快速过滤,避免不必要的类加载。真正的条件评估在 ConditionEvaluator 中完成。


完整示例

场景简述

飞翔科技(广州)的学生成绩管理系统 com.feixiang.student 基于 Spring Boot 2.7.18。架构师白歌要求小崔为公司开发一个自定义 Starter,为所有内部项目提供统一的日志追踪配置。小崔需要理解 AutoConfigurationImportSelector 读取 spring.factories 的机制,才能正确注册自定义自动配置类。

操作前:直接在启动类中写日志配置

// 操作前:错误示范,每个项目重复写日志配置
package com.feixiang.student;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

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

后果:每个新项目的启动类都要重复写 TraceIdFilter Bean 的定义。飞翔科技有 10 个内部系统,小崔就复制粘贴了 10 次。一旦过滤器的构造逻辑变更(比如需要注入 TraceProperties),10 个项目都要修改。

使用该机制的完整代码

小崔决定写一个自定义自动配置模块 feixiang-trace-spring-boot-starter,让它像官方 Starter 一样被 AutoConfigurationImportSelector 自动加载。

步骤 1:创建自动配置类

package com.feixiang.trace.autoconfigure;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;

/**
 * 飞翔科技统一日志追踪自动配置类
 * 
 * @author 小崔
 * @since 2024
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Filter.class)  // 类路径存在 Servlet API 时才生效
@ConditionalOnProperty(prefix = "feixiang.trace", name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(TraceProperties.class)
public class TraceAutoConfiguration {
    
    @Bean
    public TraceIdFilter traceIdFilter(TraceProperties properties) {
        return new TraceIdFilter(properties.getHeaderName());
    }
}

步骤 2:创建配置属性类

package com.feixiang.trace.autoconfigure;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "feixiang.trace")
public class TraceProperties {
    private boolean enabled = true;
    private String headerName = "X-Trace-Id";
    
    // getter / setter ...
    public boolean isEnabled() { return enabled; }
    public void setEnabled(boolean enabled) { this.enabled = enabled; }
    public String getHeaderName() { return headerName; }
    public void setHeaderName(String headerName) { this.headerName = headerName; }
}

步骤 3:在 spring.factories 中注册

在 feixiang-trace-spring-boot-starter 模块的 resources/META-INF/spring.factories 中写入:

# spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.feixiang.trace.autoconfigure.TraceAutoConfiguration

Spring Boot 2.7 推荐使用新文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,每行一个类名:

com.feixiang.trace.autoconfigure.TraceAutoConfiguration

两种写法在 2.7.x 中均兼容。

步骤 4:在 application.yml 中配置

# application.yml
feixiang:
  trace:
    enabled: true
    header-name: X-Feixiang-Trace-Id

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/student_db
    username: root
    password: secret

操作后运行结果及分析

启动日志(关键片段):

2024-05-20 10:15:33.123  INFO 12345 --- [main] o.s.b.a.AutoConfigurationImportSelector : 
    Loaded 147 auto-configuration candidate classes from spring.factories
2024-05-20 10:15:33.456  INFO 12345 --- [main] c.f.t.a.TraceAutoConfiguration : 
    TraceAutoConfiguration matched: 
    @ConditionalOnClass found javax.servlet.Filter, 
    @ConditionalOnProperty matched feixiang.trace.enabled=true
2024-05-20 10:15:33.789  INFO 12345 --- [main] c.f.t.a.TraceAutoConfiguration : 
    TraceIdFilter bean registered with headerName = X-Feixiang-Trace-Id

分析:

  1. AutoConfigurationImportSelector 加载:从 spring.factories 中读取到 147 个候选配置类(不同版本的 Spring Boot 数量不同),其中包括小崔自定义的 TraceAutoConfiguration。
  2. 条件评估通过:@ConditionalOnClass(Filter.class) 检测到 spring-boot-starter-web 引入了 javax.servlet.Filter,条件满足;@ConditionalOnProperty 检测到 feixiang.trace.enabled=true(或 matchIfMissing 默认生效),条件满足。
  3. 配置绑定生效:@EnableConfigurationProperties(TraceProperties.class) 将 application.yml 中的 feixiang.trace.header-name 绑定到 TraceProperties 对象,注入 traceIdFilter 方法。
  4. 优雅启动:TraceIdFilter 被注册为 Servlet Filter,所有 HTTP 请求都会自动携带 X-Feixiang-Trace-Id 请求头。

易错场景与面试考点

易错场景一:spring.factories 写错 key 导致自动配置不加载

小崔第一次写 spring.factories 时,不小心把 key 写错了:

# 错误示范:key 拼写错误
org.springframework.boot.autoconfigure.AutoConfiguration=\
com.feixiang.trace.autoconfigure.TraceAutoConfiguration

后果:AutoConfigurationImportSelector 调用 SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, ...) 时,查找的 key 是 org.springframework.boot.autoconfigure.EnableAutoConfiguration,而上面写成了 AutoConfiguration(少了 Enable)。因此 TraceAutoConfiguration 永远不会被加载,小崔在业务项目中引入 Starter 后没有任何效果。

正确做法:

# 正确 key(Spring Boot 2.7.x 兼容写法)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.feixiang.trace.autoconfigure.TraceAutoConfiguration

或直接使用新文件:

# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.feixiang.trace.autoconfigure.TraceAutoConfiguration

易错场景二:自定义自动配置类没有 proxyBeanMethods = false

// 错误示范:使用默认 proxyBeanMethods = true
@Configuration  // 默认 proxyBeanMethods = true
@ConditionalOnClass(Filter.class)
public class TraceAutoConfiguration { ... }

后果:Spring Boot 2.7.x 的自动配置类推荐设置为 proxyBeanMethods = false(即 lite 模式),因为自动配置类通常不需要通过方法调用来代理 @Bean 之间的依赖。设置为 false 可以减少 CGLIB 代理的创建,提升启动性能。虽然不设置也不会报错,但不符合 Spring Boot 官方自动配置类的规范。

正确做法:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Filter.class)
public class TraceAutoConfiguration { ... }

面试考点

Q:AutoConfigurationImportSelector 为什么要实现 DeferredImportSelector 而不是普通的 ImportSelector?

因为 DeferredImportSelector 的导入时机被推迟到所有普通 @Configuration 类处理完毕之后。这确保了用户自定义的 Bean 和显式配置先于自动配置被注册,从而让 @ConditionalOnMissingBean 能够正确判断"用户是否已经自定义了同类 Bean"。如果自动配置先于用户配置执行,条件判断会基于一个空容器,导致误判。

Q:spring.factories 中的自动配置类列表是如何被读取的?

AutoConfigurationImportSelector.getCandidateConfigurations() 方法调用 SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, getBeanClassLoader())。SpringFactoriesLoader 会扫描所有 META-INF/spring.factories 文件,以 EnableAutoConfiguration 的全限定名为 key,读取 value 中逗号分隔的类名列表,并合并去重。

Q:Spring Boot 2.7 的 AutoConfiguration.imports 新文件有什么好处?

  1. 每行一个类名,不再需要逗号分隔,可读性更好;2. 与 spring.factories 中的其他非自动配置项分离,职责更清晰;3. 避免 spring.factories 中 key 拼写错误的问题。Spring Boot 2.7 同时兼容新旧两种写法,但官方推荐新文件。

Q:自定义自动配置类被加载后,条件评估失败会怎样?

条件评估失败(如 @ConditionalOnClass 不匹配)时,该配置类被静默跳过,不会注册其中的任何 @Bean。这个"负匹配"结果会被记录到 ConditionEvaluationReport 中,当 debug=true 时可以在控制台或 Actuator /actuator/conditions 端点查看。

上一页
自动配置原理
下一页
自动配置报告