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 封装公共组件。

相关推荐
用户76280782528632 小时前
SpringBoot入门实战指南
后端
苏三说技术2 小时前
JDK17的语法变化真大,这是Java?
后端
老李的勺子2 小时前
Agent Skills 实战(1):Summarize
后端
康小庄2 小时前
JVM学习——Gc Roots
java·jvm·spring boot·学习·spring
sdanss2 小时前
Spring Boot接收参数的19种方式
java·spring boot·后端
金銀銅鐵2 小时前
Byte Buddy 生成的类的结构如何?(第一篇)
java·后端
sxhcwgcy2 小时前
Spring Cloud GateWay搭建
java
umeelove352 小时前
Spring框架
java·后端·spring
轩情吖2 小时前
MySQL之表的约束
android·数据库·c++·后端·mysql·开发·约束