1-2 自动配置原理

3 阅读2分钟

1-2 自动配置原理

概念解析

自动配置核心流程

启动类 @SpringBootApplication@EnableAutoConfiguration
        ↓
Spring Factories 加载配置类
        ↓
@Conditional 条件判断
        ↓
按需配置(需要的才生效)

关键注解

注解作用
@SpringBootApplication组合注解,包含自动配置
@EnableAutoConfiguration启用自动配置
@Import导入配置类
@Configuration标记配置类
@Conditional条件判断

代码示例

1. 查看自动配置报告

application.yml

# 开启自动配置报告(控制台输出)
debug: true

# 或者查看 web 端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

访问 http://localhost:8080/actuator/conditions 查看详细报告

2. 自定义自动配置类

步骤 1:创建配置类

package com.example.demo.config;

@Configuration
@ConditionalOnClass(UserService.class)  // 当 UserService 在 classpath 时生效
@ConditionalOnProperty(
    prefix = "app.user",
    name = "enabled",
    havingValue = "true",
    matchIfMissing = true  // 缺失时也生效
)
public class UserAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean  // 容器中不存在时才创建
    public UserService userService() {
        return new UserServiceImpl();
    }
}

步骤 2:注册配置类

# resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.config.UserAutoConfiguration

或者(Spring Boot 2.7+):

# resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.demo.config.UserAutoConfiguration

3. 排除自动配置

@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class,
    HibernateJpaAutoConfiguration.class
})
public class SpringBootApplication { }

源码解读

@SpringBootApplication 源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
    @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM,
            classes = AutoConfigurationImportFilter.class)
})
public @interface SpringBootApplication {
    // ...
}

@EnableAutoConfiguration 源码

@AutoConfigurationPackage  // 记录主类的包名
@Import(AutoConfigurationImportSelector.class)  // 关键!
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}

AutoConfigurationImportSelector 执行流程

public class AutoConfigurationImportSelector
        implements DeferredImportSelector {

    // 核心方法:返回需要导入的自动配置类
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 1. 获取 EnableAutoConfiguration 注解的属性
        // 2. 从 spring.factories 读取所有候选配置
        // 3. 根据 @Conditional 条件过滤
        // 4. 去除重复配置
        // 5. 返回最终生效的配置类名数组
    }
}

常见坑点

⚠️ 坑 1:自动配置不生效

排查步骤

  1. 检查是否被 @Conditional 排除
  2. 检查依赖是否引入
  3. 查看自动配置报告
  4. 检查是否被 exclude 排除

⚠️ 坑 2:多个配置类冲突

问题:多个候选人配置了同一个 Bean

解决:使用 @ConditionalOnMissingBean 确保只配置一个

@Bean
@ConditionalOnMissingBean(UserService.class)
public UserService userService() {
    return new UserServiceImpl();
}

⚠️ 坑 3:自动配置顺序问题

问题:配置类之间的依赖顺序不对

解决:使用 @AutoConfigureBefore / @AutoConfigureAfter

@Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyBatisAutoConfiguration { }

面试题

Q1:自动配置是怎么实现的?

参考答案

  1. @EnableAutoConfiguration 通过 @Import 导入 AutoConfigurationImportSelector

  2. selectImports() 方法执行时:

    • META-INF/spring.factories 读取所有 EnableAutoConfiguration 配置
    • 读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(2.7+)
    • 根据 @Conditional 条件进行过滤
    • 去除重复和已排除的配置
  3. 按需配置:Spring Boot 遵循"按需配置"原则,只加载符合条件的配置


Q2:spring.factories 是什么?

参考答案

spring.factories 是 Spring 框架的 SPI(Service Provider Interface)机制配置文件,格式为:

# key = 接口/抽象类
# value = 实现类(多个用逗号分隔)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.demo.config.UserAutoConfiguration,\
com.example.demo.config.OrderAutoConfiguration

注意:Spring Boot 2.7+ 推荐使用 AutoConfiguration.imports 文件替代


Q3:如何自定义 starter?

参考答案

1. 创建 autoconfigure 模块

my-starter/
└── my-starter-autoconfigure/
    ├── pom.xml
    └── src/main/java/
        └── com/example/config/
            └── MyAutoConfiguration.java

2. 创建 starter 模块

my-starter/
├── my-starter-autoconfigure/
└── my-starter/
    └── src/main/resources/
        └── META-INF/
            └── spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

3. starter 的 pom.xml 只包含依赖引用

<dependencies>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>my-starter-autoconfigure</artifactId>
        <version>1.0.0</version>
    </dependency>
</dependencies>

使用方只需引入 starter 即可

<dependency>
    <groupId>com.example</groupId>
    <artifactId>my-starter</artifactId>
</dependency>