SpringNotes

第 08 章:自动装配

zjc 于 2026-01-08 发布

这是《Spring Boot 与 Spring Cloud 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 自动装配是 Spring Boot 的核心能力:根据 classpath、已有 Bean、属性条件和环境类型,自动创建一组合理的默认配置。它不是魔法,而是条件化 BeanDefinition 注册机制。

8.1 @SpringBootApplication

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
}

职责:

注解 作用
@SpringBootConfiguration 声明配置类
@EnableAutoConfiguration 开启自动装配
@ComponentScan 扫描主类包及子包

如果主类放在错误包下,例如放在 com.example,业务代码在 com.example.order,没有显式扫描参数时默认能扫到;反之主类放在深层包而业务在外层包,就扫不到。

8.2 自动装配入口

Spring Boot 3 使用:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

Spring Boot 2 使用:

META-INF/spring.factories

自动配置类示例:

@AutoConfiguration
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnMissingBean(ObjectMapper.class)
public class JacksonAutoConfiguration {

    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }
}

自动配置不是全部加载,而是逐个评估条件。

8.3 常用条件

注解 条件
@ConditionalOnClass 类存在
@ConditionalOnMissingClass 类不存在
@ConditionalOnBean Bean 存在
@ConditionalOnMissingBean Bean 不存在
@ConditionalOnProperty 属性匹配
@ConditionalOnResource 资源存在
@ConditionalOnWebApplication Web 应用
@ConditionalOnNotWebApplication 非 Web 应用
@ConditionalOnExpression SpEL 为 true
@AutoConfigureBefore / @AutoConfigureAfter 配置顺序

示例:

@Bean
@ConditionalOnProperty(prefix = "app.cache", name = "enabled", havingValue = "true")
public LocalCache localCache() {
    return new LocalCache();
}

8.4 自动装配报告

启动时开启 debug:

java -jar app.jar --debug

输出:

Positive matches:
  JacksonAutoConfiguration matched:
     - @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper'

Negative matches:
  DataSourceAutoConfiguration did not match:
     - @ConditionalOnClass did not find required class 'javax.sql.DataSource'

也可以通过 Actuator:

/actuator/conditions

排查思路:

看配置类是否匹配
  -> 看 Positive / Negative 原因
  -> 检查依赖
  -> 检查属性
  -> 检查用户是否覆盖 Bean

8.5 用户配置优先

自动配置通常使用 @ConditionalOnMissingBean

@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource defaultDataSource() {
    return embeddedDataSource();
}

用户覆盖:

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        return customDataSource();
    }
}

这样用户配置优先,框架提供默认值。为了避免误覆盖,覆盖重要 Bean 时应清楚版本行为和配置类的 @AutoConfigureBefore 顺序。

8.6 自动配置顺序

@AutoConfiguration
@AutoConfigureAfter(CacheAutoConfiguration.class)
public class ReportAutoConfiguration {
}

顺序影响:

  1. @ConditionalOnBean 的判断结果;
  2. Bean 初始化顺序;
  3. 代理生成;
  4. 属性绑定;
  5. Bean 覆盖关系。

在 Starter 中应显式声明顺序,而不是依赖偶然加载顺序。

8.7 编写一个自动配置

业务客户端:

public class SmsClient {
    private final String endpoint;
    private final RestClient restClient;

    public SmsClient(String endpoint, RestClient restClient) {
        this.endpoint = endpoint;
        this.restClient = restClient;
    }

    public void send(String phone, String content) {
        restClient.post().uri(endpoint).body(Map.of("phone", phone, "content", content)).retrieve().toBodilessEntity();
    }
}

配置属性:

@ConfigurationProperties(prefix = "sms")
public record SmsProperties(String endpoint, Duration timeout) {
}

自动配置:

@AutoConfiguration
@EnableConfigurationProperties(SmsProperties.class)
@ConditionalOnClass(SmsClient.class)
public class SmsAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(SmsClient.class)
    public SmsClient smsClient(SmsProperties properties, RestClient.Builder builder) {
        return new SmsClient(properties.endpoint(), builder.build());
    }
}

Spring Boot 3 注册文件:

src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

内容:

com.example.sms.SmsAutoConfiguration

8.8 测试自动配置

验证默认创建:

@SpringBootTest(properties = "sms.endpoint=http://localhost:8080")
class SmsAutoConfigurationTests {

    @Autowired
    private SmsClient smsClient;

    @Test
    void shouldCreateDefaultClient() {
        assertThat(smsClient).isNotNull();
    }
}

验证条件不满足:

@SpringBootTest(properties = "sms.enabled=false")
class SmsDisabledTests {

    @Autowired
    private ApplicationContext context;

    @Test
    void shouldNotCreateClient() {
        assertThat(context.containsBean("smsClient")).isFalse();
    }
}

必须覆盖:

  1. 默认创建;
  2. 用户覆盖;
  3. 条件不满足;
  4. 配置校验失败;
  5. 版本兼容。

8.9 常见坑

问题 原因
自动配置未生效 注册文件路径错误
条件不匹配 依赖缺失、属性错误
Bean 被意外覆盖 @ConditionalOnMissingBean
顺序不稳定 未声明 @AutoConfigureAfter
属性没有提示 缺少 metadata
版本不兼容 Starter 与 Boot 版本不匹配
打包后可用 IDE 不可用 resources 未进入 jar

配置提示依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

本章小结

自动装配通过注册文件和条件注解,把常见配置变成可推导的默认行为。Spring Boot 3 使用 AutoConfiguration.imports,旧版本使用 spring.factories。排查时要善用 debug 自动装配报告,理解 Positive/Negative matches。设计 Starter 时应显式声明条件、顺序、属性绑定和测试矩阵。

思考题

  1. @ComponentScan 和自动装配有什么区别?
  2. Spring Boot 2 与 3 的自动装配注册方式有何不同?
  3. @ConditionalOnMissingBean 为什么能让用户配置优先?
  4. 自动配置顺序为什么会影响条件判断?
  5. 如何为 Starter 写完整自动化测试?