Skip to content
清晨的一缕阳光
返回

Spring Boot 自动配置原理详解

前言

自动配置是 Spring Boot 最核心的特性之一。它让我们无需繁琐的 XML 配置,只需引入 starter 依赖,Spring Boot 就能自动配置好相应的 Bean。本文将深入剖析自动配置的实现原理。

自动配置是什么

传统 Spring 的配置

在传统 Spring 应用中,我们需要手动配置大量 Bean:

@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/demo");
        config.setUsername("root");
        config.setPassword("123456");
        config.setDriverClassName("com.mysql.cj.jdbc.Driver");
        return new HikariDataSource(config);
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

Spring Boot 的自动配置

在 Spring Boot 中,只需引入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>

然后在配置文件中简单配置:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo
    username: root
    password: 123456

Spring Boot 会自动创建 DataSource、JdbcTemplate 等 Bean。

核心注解

@SpringBootApplication

@SpringBootApplication 是 Spring Boot 的核心注解,它是一个组合注解:

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

关键注解:

@EnableAutoConfiguration

@EnableAutoConfiguration 是自动配置的核心:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    // ...
}

关键是通过 @Import(AutoConfigurationImportSelector.class) 导入自动配置类。

自动配置流程

1. AutoConfigurationImportSelector

AutoConfigurationImportSelector 负责加载所有自动配置类:

public class AutoConfigurationImportSelector implements DeferredImportSelector {
    
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 获取所有自动配置类
        List<String> configurations = getCandidateConfigurations(
            annotationMetadata.getAnnotationAttributes(EnableAutoConfiguration.class.getName())
        );
        // 去重
        configurations = removeDuplicates(configurations);
        // 排除不需要的配置
        configurations = getExclusionFilter().filter(configurations);
        // 返回配置类列表
        return configurations.toArray(new String[0]);
    }
    
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        // 加载 META-INF/spring.factories 中的配置
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
            EnableAutoConfiguration.class, getClassLoader()
        );
        return configurations;
    }
}

2. SPI 机制

Spring Boot 使用 SPI(Service Provider Interface)机制加载自动配置类:

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

Spring Boot 4 中,spring.factories 迁移到新的位置:

# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration

3. 条件注解

自动配置类使用条件注解控制是否生效:

@Configuration
@ConditionalOnClass({DataSource.class, JdbcTemplate.class})
@ConditionalOnMissingBean(JdbcTemplate.class)
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcTemplateAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
        return new JdbcTemplate(dataSource);
    }
}

常用条件注解:

注解说明
@ConditionalOnClass类路径存在指定类时生效
@ConditionalOnMissingClass类路径不存在指定类时生效
@ConditionalOnBean容器中存在指定 Bean 时生效
@ConditionalOnMissingBean容器中不存在指定 Bean 时生效
@ConditionalOnProperty配置属性满足条件时生效
@ConditionalOnWebApplicationWeb 应用时生效
@ConditionalOnExpressionSpEL 表达式为 true 时生效

自定义自动配置

1. 创建配置类

@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnMissingBean(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
    
    @Bean
    public MyService myService(MyProperties properties) {
        return new MyService(properties.getPrefix());
    }
}

2. 创建配置属性类

@ConfigurationProperties(prefix = "my")
public class MyProperties {
    
    private String prefix = "default";
    
    // getters and setters
    public String getPrefix() {
        return prefix;
    }
    
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }
}

3. 注册自动配置

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

4. 测试自动配置

@SpringBootTest
public class MyAutoConfigurationTest {
    
    @Autowired
    private MyService myService;
    
    @Test
    public void testMyService() {
        assertNotNull(myService);
    }
}

调试自动配置

1. 启用调试日志

logging:
  level:
    org.springframework.boot.autoconfigure: DEBUG

2. 使用 ConditionEvaluationReport

启动时添加参数:

--debug

查看自动配置报告:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(DemoApplication.class);
        app.addListeners(event -> {
            if (event instanceof ApplicationReadyEvent) {
                ConditionEvaluationReport report = 
                    ((ConfigurableApplicationContext) event.getApplicationContext())
                        .getBean(ConditionEvaluationReport.class);
                // 打印自动配置报告
            }
        });
        app.run(args);
    }
}

3. 排除自动配置

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

或者:

spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
      - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

自动配置顺序

Spring Boot 4 支持通过 @AutoConfigureOrder 控制自动配置顺序:

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class FirstAutoConfiguration {
    // ...
}

@Configuration
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
public class LastAutoConfiguration {
    // ...
}

也可以使用 @AutoConfigureBefore 和 @AutoConfigureAfter:

@Configuration
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
public class CustomDataSourceAutoConfiguration {
    // ...
}

总结

自动配置是 Spring Boot 的核心特性:

理解自动配置原理,能帮助你更好地使用 Spring Boot,并在需要时进行扩展和定制。


分享这篇文章到:

上一篇文章
Feign 高级特性
下一篇文章
事件驱动架构