专栏文章
专栏文章
SpringBoot 系列
1. SpringBoot 系列 #01:SpringBoot 启动流程源码分析 2. SpringBoot 系列 #02:SpringBoot 日志集成原理 3. SpringBoot 系列 #03:SpringBoot 自动装配原理

SpringBoot 系列 #03:SpringBoot 自动装配原理

发布于 2026-05-26 09:43 👁 8 次阅读
#源码解析#spring#spring-boot

本文从 @SpringBootApplication 出发,逐层深入剖析 Spring Boot 自动装配的触发机制、SPI 加载、条件过滤全流程,并给出自定义 Starter 的完整实现方案。


目录

章节 说明
整体架构 核心注解关系与组件职责
核心流程 从启动到 Bean 注册的完整链路
源码分析 关键类与方法逐行解读
条件注解 @ConditionalOnXxx 全家桶
自定义 Starter 编写可复用的自动装配模块
最佳实践 生产环境排查与调优建议
常见问题 典型故障与排查思路

整体架构

注解层级关系

graph TD
    A["@SpringBootApplication"] --> B["@SpringBootConfiguration"]
    A --> C["@ComponentScan"]
    A --> D["@EnableAutoConfiguration"]
    D --> E["@AutoConfigurationPackage"]
    D --> F["@Import(AutoConfigurationImportSelector)"]
    F --> G["AutoConfigurationImportSelector"]
    G --> H["SpringFactoriesLoader<br/>(Boot < 2.7)"]
    G --> I["ImportCandidates<br/>(Boot ≥ 2.7)"]
    H --> J["META-INF/spring.factories"]
    I --> K["META-INF/spring/<br/>AutoConfiguration.imports"]
    style D fill:#cfc,stroke:#060
    style G fill:#cfc,stroke:#060

核心组件职责

组件 所在包 职责
@EnableAutoConfiguration spring-boot-autoconfigure 开关注解,触发自动装配
AutoConfigurationImportSelector spring-boot-autoconfigure SPI 加载 + 条件过滤的核心选择器
SpringFactoriesLoader spring-core 读取 spring.factories 的工具类
ImportCandidates spring-boot Boot 2.7+ 读取 .imports 文件
@Conditional 系列 spring-context 按条件决定 Bean 是否注册

核心流程

触发时机

自动装配的入口在 Spring 容器刷新阶段(AbstractApplicationContext#refresh),由 ConfigurationClassParser 解析 @Import 注解时触发 DeferredImportSelector

sequenceDiagram
    participant App as SpringApplication
    participant Ctx as AnnotationConfigApplicationContext
    participant Parser as ConfigurationClassParser
    participant Selector as AutoConfigurationImportSelector
    participant Loader as SpringFactoriesLoader

    App->>Ctx: refresh()
    Ctx->>Parser: parse(@SpringBootApplication)
    Parser->>Parser: 解析 @EnableAutoConfiguration
    Parser->>Selector: selectImports()
    Selector->>Loader: loadFactoryNames() / loadAutoConfigurationClasses()
    Loader-->>Selector: 候选配置类列表(100+个)
    Selector->>Selector: 条件过滤(@ConditionalOnXxx)
    Selector-->>Parser: 过滤后的配置类列表
    Parser->>Ctx: 注册为 BeanDefinition

加载文件路径对比

Boot 版本 配置文件 读取方式
< 2.7 META-INF/spring.factories SpringFactoriesLoader.loadFactoryNames()
≥ 2.7 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports ImportCandidates.load()
3.x 同 2.7+,spring.factories 仍向后兼容但不推荐 ImportCandidates.load()

为什么 2.7+ 改用 .imports 文件?

① 性能:避免解析大文件

spring.factories 是通用 SPI,启动时为了找 EnableAutoConfiguration 一个 key,却要解析整个文件——Spring Boot 官方的 spring.factories 混了 100+ 条目(ApplicationContextInitializerEnvironmentPostProcessor 等各种用途)。新文件专职自动配置,无需扫描无关内容。

② 关注点分离

spring.factories 是"大杂烩",职责太多。将自动配置类单独提取到独立文件,语义清晰,也便于 IDE 和静态分析工具精确识别哪些是自动配置类。

③ AOT / GraalVM Native Image 支持

Spring Boot 3.x 的核心目标之一是支持编译期 AOT 和 GraalVM 原生镜像。spring.factories 依赖运行时反射加载,难以静态分析;.imports 文件格式在编译期可被处理,生成反射元数据,不需要运行时动态发现。

④ 配合 @AutoConfiguration 注解

新格式配合 Spring Boot 2.7+ 新增的 @AutoConfiguration@Configuration + 禁止被 @ComponentScan 扫到的语义),明确区分"框架自动配置类"和"用户 @Configuration 类",避免混淆。


源码分析

关键类一览

类名 模块 职责
AutoConfigurationImportSelector autoconfigure 实现 DeferredImportSelector,核心入口
AutoConfigurationMetadataLoader autoconfigure 加载 spring-autoconfigure-metadata.properties,用于快速过滤
ConditionEvaluator spring-context 执行 @Conditional 条件判断
OnClassCondition autoconfigure @ConditionalOnClass 的实现

getAutoConfigurationEntry 核心方法

// AutoConfigurationImportSelector#getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(
        AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 1. 从 spring.factories 或 .imports 文件加载全部候选类
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 2. 去重
    configurations = removeDuplicates(configurations);
    // 3. 排除 exclude 指定的类
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    // 4. 通过 AutoConfigurationImportFilter 做轻量级条件过滤(不初始化 Bean)
    configurations = getConfigurationClassFilter().filter(configurations);
    // 5. 触发 AutoConfigurationImportEvent 事件
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

关键点:第 4 步的 filter 使用 spring-autoconfigure-metadata.properties快速预过滤(不加载类),避免大量反射,这是性能优化的核心手段。

getCandidateConfigurations 加载入口

// AutoConfigurationImportSelector#getCandidateConfigurations
protected List<String> getCandidateConfigurations(
        AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // Boot 2.7+ 优先走 ImportCandidates
    List<String> configurations = new ArrayList<>(
        SpringFactoriesLoader.loadFactoryNames(
            getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
    ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
        .forEach(configurations::add);
    return configurations;
}

spring.factories 文件格式(Boot < 2.7)

# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
  org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
  org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

AutoConfiguration.imports 文件格式(Boot ≥ 2.7)

# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

条件注解

条件注解是自动装配"按需生效"的核心机制,所有条件注解都基于 @Conditional + Condition 接口实现。

常用条件注解全览

注解 生效条件 典型用途
@ConditionalOnClass classpath 中存在指定类 依赖可选时
@ConditionalOnMissingClass classpath 中不存在指定类 互斥依赖
@ConditionalOnBean 容器中已有指定 Bean 依赖其他 Bean
@ConditionalOnMissingBean 容器中没有指定 Bean 允许用户覆盖
@ConditionalOnProperty 配置属性值匹配 开关控制
@ConditionalOnWebApplication 是 Web 应用 Web 专属配置
@ConditionalOnNotWebApplication 非 Web 应用 非 Web 配置
@ConditionalOnResource classpath 中存在指定资源文件 配置文件存在
@ConditionalOnExpression SpEL 表达式为 true 复杂条件

典型用法示例

@Configuration
// classpath 有 RedisConnectionFactory 才生效
@ConditionalOnClass(RedisConnectionFactory.class)
// 没有用户自定义的 RedisTemplate 时才注册默认实现
@ConditionalOnMissingBean(name = "redisTemplate")
// 配置项 spring.data.redis.enabled=true(默认 true)时生效
@ConditionalOnProperty(prefix = "spring.data.redis", name = "enabled",
        matchIfMissing = true)
public class RedisAutoConfiguration {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(
            RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        return template;
    }
}

核心设计理念@ConditionalOnMissingBean 是"用户优先"原则的实现——用户显式定义的 Bean 永远比自动装配的优先级高。


自定义 Starter

命名规范

类型 命名规范 示例
官方 Starter spring-boot-starter-{name} spring-boot-starter-redis
第三方 Starter {name}-spring-boot-starter mybatis-spring-boot-starter

推荐目录结构

my-spring-boot-starter/
├── src/main/java/
│   └── com/example/
│       ├── MyProperties.java          ← 配置属性类
│       ├── MyService.java             ← 核心服务
│       └── MyAutoConfiguration.java  ← 自动装配类
└── src/main/resources/
    └── META-INF/spring/
        └── org.springframework.boot.autoconfigure.AutoConfiguration.imports

实现步骤

第一步:定义配置属性类

@ConfigurationProperties(prefix = "my.service")
public class MyProperties {
    private boolean enabled = true;
    private String endpoint = "http://localhost:8080";
    // getter / setter
}

第二步:编写自动装配类

@AutoConfiguration                            // Boot 2.7+ 替代 @Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(prefix = "my.service",
        name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MyService myService(MyProperties props) {
        return new MyService(props.getEndpoint());
    }
}

第三步:注册自动装配类(Boot ≥ 2.7)

# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.MyAutoConfiguration

第四步:声明 pom 依赖

<dependencies>
    <!-- 提供 @ConfigurationProperties 等注解处理器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
    <!-- 可选:生成 IDE 配置提示 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

最佳实践

调试自动装配

# 启动时打印自动装配报告(哪些生效、哪些被排除及原因)
java -jar app.jar --debug

# 或在 application.yaml 中配置
logging:
  level:
    org.springframework.boot.autoconfigure: DEBUG

排除不需要的自动装配

// 方式一:注解排除
@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class,
    RedisAutoConfiguration.class
})

// 方式二:配置文件排除(不改代码,推荐)
spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

控制自动装配顺序

@AutoConfiguration
// 在 DataSourceAutoConfiguration 之后执行
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
// 在 CacheAutoConfiguration 之前执行
@AutoConfigureBefore(CacheAutoConfiguration.class)
public class MyAutoConfiguration { }

常见问题

现象 可能原因 排查方向
自定义 Starter 的 Bean 未注册 .imports 文件路径错误或未打包 检查 META-INF/spring/ 目录,用 jar tf 确认文件存在
自动装配类生效但配置未生效 @EnableConfigurationProperties 漏写 在自动装配类上补加该注解
两个 Starter 的 Bean 冲突 缺少 @ConditionalOnMissingBean 在默认 Bean 上加条件注解,让用户可覆盖
Boot 3.x 升级后自动装配失效 仍用 spring.factories 旧格式 迁移到 AutoConfiguration.imports 文件
调试模式下看不到某配置类 该类在预过滤阶段就被排除 检查 spring-autoconfigure-metadata.properties 中对应条件

参考资料

← 返回列表

评论 (0)

暂无评论,来留下第一条吧。

发表评论