Spring Boot 自动配置原理深度解析

1. Spring Boot 核心优势

Spring Boot 的核心优势在于约定优于配置,它通过自动配置机制大幅简化了 Spring 应用的搭建和开发过程。

传统 Spring 开发需要大量 XML 配置或 Java Config:

java 复制代码
@Configuration
public class AppConfig {
    
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        config.setUsername("root");
        config.setPassword("123456");
        return new HikariDataSource(config);
    }
    
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource());
        return factory.getObject();
    }
}

Spring Boot 只需引入依赖即可:

yaml 复制代码
# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: 123456

2. @SpringBootApplication 解析

2.1 三个核心注解

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
    
    // 指定要扫描的包(默认当前包及其子包)
    @ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
    })
    Class<?>[] exclude() default {};
    
    // 指定自动配置要排除的类
    String[] excludeName() default {};
    
    // 指定扫描的包
    String[] basePackages() default {};
}

2.2 三个注解的作用

注解 作用
@SpringBootConfiguration 标识这是一个 Spring Boot 配置类,等价于 @Configuration
@EnableAutoConfiguration 启用自动配置机制
@ComponentScan 组件扫描,默认扫描当前包及其子包中的 @Component

3. @EnableAutoConfiguration 原理

3.1 注解定义

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    
    // 配置类名称,用于排除
    String[] exclude() default {};
    
    // 排除的配置类名称
    String[] excludeName() default {};
    
    // 配置类搜索路径
    String[] value() default {};
}

3.2 自动配置导入选择器

@EnableAutoConfiguration 通过 @Import 导入 AutoConfigurationImportSelector,该类实现了 ImportSelector 接口:

java 复制代码
public class AutoConfigurationImportSelector 
        implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware {
    
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 获取自动配置类
        List<String> configurations = getAutoConfigurations(annotationMetadata);
        // 排除用户已手动配置的类
        configurations = removeDuplicates(configurations);
        // 排除明确排除的类
        Set<String> exclusions = getExclusions(annotationMetadata, configurations);
        configurations.removeAll(exclusions);
        
        // 过滤:检查条件注解是否满足
        configurations = filter(configurations, autoConfigurationMetadata);
        
        // 生成 @Import 需要的类名数组
        String[] autoConfigurations = 
            configurations.toArray(new String[0]);
        // 触发 AutoConfigurationImportEvent 事件
        fireAutoConfigurationImportEvents(configurations, exclusions);
        
        return autoConfigurations;
    }
}

3.3 自动配置类加载流程

@SpringBootApplication 启动
扫描 @EnableAutoConfiguration
AutoConfigurationImportSelector.selectImports
SpringFactoriesLoader.loadFactoryNames
META-INF/spring.factories
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
过滤不满足条件的配置类
返回需要导入的配置类
注册到 Spring 容器

4. 自动配置类加载机制

4.1 Spring Boot 2.7+ 变化

Spring Boot 2.7 之前使用 META-INF/spring.factories

properties 复制代码
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

Spring Boot 2.7+ 推荐使用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

properties 复制代码
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (每行一个)
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

4.2 Spring Boot 3.x

Spring Boot 3.x 完全移除了 spring.factories,只支持 AutoConfiguration.imports 文件。

4.3 loadFactoryNames 实现

java 复制代码
public abstract class SpringFactoriesLoader {
    
    public static List<String> loadFactoryNames(
            Class<?> factoryType,
            @Nullable ClassLoader classLoader) {
        
        // factoryType = EnableAutoConfiguration.class
        String factoryTypeName = factoryType.getName();
        
        // 从 classpath 加载所有 META-INF/spring.factories
        // 并解析为 Properties
        result = loadSpringFactories(classLoader);
        
        // 获取对应类型的值
        return result.getOrDefault(factoryTypeName, Collections.emptyList());
    }
    
    private static Map<String, List<String>> loadSpringFactories(
            @Nullable ClassLoader classLoader) {
        
        // 缓存
        if (cache.containsKey(classLoader)) {
            return cache.get(classLoader);
        }
        
        // 加载所有 spring.factories 文件
        Enumeration<URL> urls = classLoader.getResources(
            "META-INF/spring.factories");
        
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            // 解析 Properties
            Properties properties = PropertiesLoaderUtils.loadProperties(url);
            // 合并到 result
            result.addAll(properties);
        }
        
        cache.put(classLoader, result);
        return result;
    }
}

5. 自动配置条件注解

Spring Boot 使用条件注解控制配置类的生效条件。

5.1 常用条件注解

注解 作用
@ConditionalOnClass 当 classpath 存在指定类时生效
@ConditionalOnMissingClass 当 classpath 不存在指定类时生效
@ConditionalOnBean 当容器中存在指定 Bean 时生效
@ConditionalOnMissingBean 当容器中不存在指定 Bean 时生效
@ConditionalOnProperty 当配置属性满足条件时生效
@ConditionalOnResource 当资源存在时生效
@ConditionalOnWebApplication 当是 Web 应用时生效

5.2 条件注解示例

java 复制代码
// 只有存在 Druid 数据源时才配置
@ConditionalOnClass(DruidDataSource.class)
@Configuration
public class DruidConfig {
    
    @ConditionalOnMissingBean(DataSource.class)
    @Bean
    public DataSource dataSource() {
        return new DruidDataSource();
    }
}

// 只有配置了 spring.redis.host 时才配置
@ConditionalOnProperty(prefix = "spring.redis", name = "host")
@Configuration
public class RedisConfig {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory connectionFactory) {
        return new RedisTemplate<>(connectionFactory);
    }
}

// 只有在 Web 应用中才配置
@ConditionalOnWebApplication
@Configuration
public class WebMvcConfig {
    
    // Web 相关配置
}

5.3 条件注解原理

java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
    
    Class<?>[] value() default {};
    
    String[] name() default {};
}

@Conditional 是 Spring 4.0 引入的通用条件注解,OnClassCondition 是其具体实现:

java 复制代码
@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition implements ConfigurationCondition {
    
    @Override
    public ConditionOutcome getMatchOutcome(
            ConditionContext context, 
            AnnotatedTypeMetadata metadata) {
        
        // 获取 @ConditionalOnClass 注解的属性
        MultiValueMap<String, Object> attributes = 
            metadata.getAllAnnotationAttributes(
                ConditionalOnClass.class.getName());
        
        List<Object> classesToCheck = attributes.get("value");
        
        // 检查 classpath 是否存在这些类
        for (Object classToCheck : classesToCheck) {
            if (!ClassUtils.isPresent(
                    classToCheck.toString(), 
                    context.getClassLoader())) {
                // 不存在,返回不匹配
                return ConditionOutcome.noMatch(
                    "@ConditionalOnClass " + classToCheck + " not present");
            }
        }
        
        return ConditionOutcome.match();
    }
}

6. 自动配置执行流程

6.1 SpringApplication 启动流程

AutoConfiguration ApplicationContext SpringApplication main() AutoConfiguration ApplicationContext SpringApplication main() run(args) createApplicationContext() refresh(context) invokeBeanFactoryPostProcessors() 处理 @Configuration 类的 @Bean 加载 AutoConfiguration 按条件过滤 注册 AutoConfiguration Bean ApplicationContext 准备完毕

6.2 配置类解析

Spring Boot 的自动配置类本质上是一个 @Configuration 类:

java 复制代码
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(EmbeddedServletContainer.class)
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class WebServerAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean(TomcatServletWebServerFactory.class)
    public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }
}

7. 自定义 Starter

7.1 命名规范

类型 命名规范 示例
官方 Starter spring-boot-starter-* spring-boot-starter-web
第三方 Starter *-spring-boot-starter druid-spring-boot-starter

7.2 实现步骤

第一步:创建自动配置类

java 复制代码
@Configuration
@ConditionalOnProperty(prefix = "myapp", name = "enabled", 
    havingValue = "true", matchIfMissing = true)
public class MyAppAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public MyService myService() {
        return new MyService();
    }
}

第二步:创建 spring.factories 或 imports 文件

复制代码
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.myapp.MyAppAutoConfiguration

复制代码
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.myapp.MyAppAutoConfiguration

第三步:创建配置属性类

java 复制代码
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
    
    private String name = "default";
    
    private int timeout = 3000;
    
    // getters and setters
}

第四步:在启动类启用

java 复制代码
@SpringBootApplication
@EnableConfigurationProperties(MyAppProperties.class)
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

7.3 使用自定义 Starter

yaml 复制代码
# application.yml
myapp:
  enabled: true
  name: my-app
  timeout: 5000
java 复制代码
@RestController
public class TestController {
    
    @Autowired
    private MyService myService;
    
    @GetMapping("/test")
    public String test() {
        return myService.sayHello();
    }
}

8. 自动配置源码层级

8.1 核心层级

Spring Boot 启动类

@SpringBootApplication
@EnableAutoConfiguration
AutoConfigurationImportSelector
SpringFactoriesLoader
META-INF/spring.factories

META-INF/spring/xxx.imports
加载所有 AutoConfiguration
@Conditional 条件过滤
实例化配置类

注册 Bean

8.2 配置类注册流程

java 复制代码
// AbstractApplicationContext.refresh()
public void refresh() {
    // ...
    // 7. 初始化 BeanFactory 扩展
    invokeBeanFactoryPostProcessors(beanFactory);
    // ...
    // 11. 初始化所有单例 Bean
    finishBeanFactoryInitialization(beanFactory);
}

9. 常见自动配置类

9.1 DataSourceAutoConfiguration

java 复制代码
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
    
    @Configuration(proxyBeanMethods = false)
    @Conditional(DataSourceAutoConfiguration.PooledDataSourceCondition.class)
    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    @Import(DataSourceConfiguration.Hikari.class)
    protected static class Hikari {
        // 配置 HikariCP 连接池
    }
}

9.2 RedisAutoConfiguration

java 复制代码
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置序列化器
        return template;
    }
    
    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory connectionFactory) {
        return new StringRedisTemplate(connectionFactory);
    }
}

9.3 WebMvcAutoConfiguration

java 复制代码
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@ConditionalOnClass({ WebMvcConfigurer.class })
@EnableConfigurationProperties({ WebMvcProperties.class })
@Import({ WebMvcAutoConfiguration.EnableWebMvcConfiguration.class })
public class WebMvcAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
            @Qualifier("mvcContentNegotiationManager") 
            ContentNegotiationManager contentNegotiationManager,
            @Qualifier("mvcConversionService") 
            FormattingConversionService conversionService,
            @Qualifier("mvcResourceUrlProvider") 
            ResourceUrlProvider resourceUrlProvider) {
        // 配置请求映射
    }
}

10. 最佳实践

10.1 排除不需要的自动配置

java 复制代码
// 方式1:启动类排除
@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class,
    RedisAutoConfiguration.class
})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 方式2:application.yml 排除
spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
      - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

10.2 查看自动配置报告

bash 复制代码
# 启用 debug 模式
java -jar app.jar --debug

# 或 application.yml
spring:
  main:
    log-startup-info: true

输出类似:

复制代码
=========================
AUTO-CONFIGURATION REPORT
=========================

Positive matches:
-----------------
    DataSourceAutoConfiguration
    - @ConditionalOnClass found on class 'javax.sql.DataSource' 
      (OnClassCondition)
    - @ConditionalOnMissingBean (types: javax.sql.DataSource;SearchStrategy: all) 
      did not find any beans (OnBeanCondition)

Negative matches:
-----------------
    RedisAutoConfiguration
    - @ConditionalOnClass did not find 'org.springframework.data.redis.core.RedisOperations' 
      (OnClassCondition)

10.3 自定义配置优先级

java 复制代码
// 1. 配置属性类(最高优先级)
// application.yml 中配置

// 2. @Bean 定义
@Bean
public DataSource dataSource() {
    return new HikariDataSource();
}

// 3. 自动配置默认值
// application.yml 未配置时使用

11. 总结

Spring Boot 自动配置是其核心优势,理解其原理对面试和开发都非常重要。

  • @SpringBootApplication 组合了 @Configuration@EnableAutoConfiguration@ComponentScan 三个注解
  • 自动配置 通过 SpringFactoriesLoader 加载 META-INF/spring.factoriesAutoConfiguration.imports 文件
  • 条件注解@ConditionalOnClass@ConditionalOnBean 等)控制配置类的生效条件
  • 配置类 本质上是一个标注了 @Configuration 的普通 Spring 配置类
  • 自定义 Starter 需要创建自动配置类和对应的配置文件

掌握这些知识点,能够帮助你更好地理解 Spring Boot 的工作原理,也能够自定义 Starter 封装公共组件。

相关推荐
鱼鳞_7 小时前
Java学习笔记_Day22
java·笔记·学习
老马95277 小时前
opencode2-初步体验
人工智能·后端
常利兵7 小时前
细说API:颠覆认知!重新认识RESTful的真正精髓
后端·restful
__土块__7 小时前
一次电商秒杀系统架构评审:从本地锁到分布式锁的演进与取舍
java·redis·高并发·分布式锁·redisson·架构设计·秒杀系统
她说..7 小时前
Java 注解核心面试题
java·spring boot·spring·spring cloud·自定义注解
用户8307196840827 小时前
Spring Boot @Qualifier深度解密:从“按名查找”到“分组批量注入”,一文掌握它的全部“隐藏技能”。
java·spring boot
亦暖筑序7 小时前
Message 四分天下:Spring AI 如何统一消息格式
java·人工智能
镜花水月linyi8 小时前
JDK 8 → 17 → 21 → 25:一次性讲清四代版本的关键跃迁
java·后端
啷里格啷8 小时前
Day5 【补充】线程模型与异步处理
后端
Java水解8 小时前
Spring Security 最佳实践:2026 实战指南
后端