基于本文回答
0
评论

Spring Boot 的“自动配置”(Auto-Configuration)原理

知识点图片

Spring Boot 自动配置(Auto-Configuration)是其核心特性之一,它体现了 “约定优于配置” (Convention over Configuration) 的设计理念。

简单来说,它的原理就是:在应用启动时,Spring Boot 会根据你引入的 Jar 包(Classpath)、配置文件(Properties/YAML)以及你自定义的 Bean,自动猜测并配置你可能需要的 Bean 到 Spring 容器中。

下面深入源码和机制,分步骤解析其底层原理:


1. 入口:@SpringBootApplication

一切始于主启动类上的 @SpringBootApplication 注解。这是一个组合注解,其中最关键的是 @EnableAutoConfiguration

java
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

@SpringBootApplication 实际上包含了三个核心注解:

  1. @SpringBootConfiguration:声明当前类是一个配置类。
  2. @ComponentScan:扫描当前包及其子包下的组件。
  3. @EnableAutoConfiguration开启自动配置的核心

2. 核心开关:@EnableAutoConfiguration

@EnableAutoConfiguration 的作用是告诉 Spring Boot:“请帮我自动配置 Bean”。它内部使用了 @Import 注解来导入配置加载器。

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

这里的关键是 @Import(AutoConfigurationImportSelector.class)


3. 选择器:AutoConfigurationImportSelector

AutoConfigurationImportSelector 类实现了 DeferredImportSelector 接口。它的主要职责是在 Spring 容器启动过程中,根据一定的规则选择需要导入的配置类。

其核心流程如下:

  1. 加载所有候选配置类
    它会去寻找所有 Jar 包中特定的配置文件,读取其中列出的自动配置类全限定名。

    • Spring Boot 2.7 之前:读取 META-INF/spring.factories 文件(Key 为 EnableAutoConfiguration)。
    • Spring Boot 2.7 及 3.x:读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件。

    例子(spring-boot-autoconfigure.jar 中):
    里面包含了大量的配置类,如 RedisAutoConfigurationJdbcTemplateAutoConfiguration 等。

  2. 去重与排除
    去除重复的配置类,并根据 @EnableAutoConfiguration(exclude=...) 排除掉用户明确不需要的配置类。

  3. 按需过滤(核心逻辑)
    虽然加载了上百个自动配置类,但不能全部生效,否则应用会极其臃肿且报错。这里就需要用到 条件注解(Conditional Annotations)


4. 智能过滤:@Conditional 派生注解

这是自动配置最“智能”的地方。每个自动配置类(如 RedisAutoConfiguration)上面都挂满了 @Conditional 系列注解。只有满足所有条件,该配置类才会生效,Bean 才会被注册到容器中。

常见的条件注解包括:

  • @ConditionalOnClass:当 Classpath 中存在指定的类时才生效。(例如:只有引入了 spring-boot-starter-data-redis,Classpath 里有了 Redis 相关类,Redis 的自动配置才会生效)。
  • @ConditionalOnMissingBean:当容器中没有用户自定义的同类型 Bean 时才生效。(这允许用户手动定义 Bean 来覆盖默认配置)。
  • @ConditionalOnProperty:当配置文件中有指定的属性且值为特定值时才生效。
  • @ConditionalOnWebApplication:只有在 Web 应用环境下才生效。

举个例子(HttpEncodingAutoConfiguration):

java
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) // 1. 必须是 Web 应用
@ConditionalOnClass(CharacterEncodingFilter.class) // 2. 必须有这个过滤器类
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) // 3. 配置没关
public class HttpEncodingAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean // 4. 如果用户没自己配,我就配一个
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        // 设置编码...
        return filter;
    }
}

5. 属性绑定:@ConfigurationProperties

自动配置类通常需要读取 application.propertiesapplication.yml 中的配置。这是通过 @ConfigurationProperties 实现的。

  1. 定义一个 Properties 类(如 ServerProperties),使用 @ConfigurationProperties(prefix = "server") 绑定配置文件前缀。
  2. 在自动配置类上使用 @EnableConfigurationProperties(ServerProperties.class) 激活它。
  3. 自动配置类就可以直接注入 ServerProperties 并使用其中的值来初始化 Bean。

总结:自动配置的完整流程

  1. 启动:Spring Boot 应用启动,加载主配置类,解析 @EnableAutoConfiguration
  2. 导入AutoConfigurationImportSelector 被调用。
  3. 扫描:扫描所有 Jar 包下的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (或旧版的 spring.factories),获取所有候选的自动配置类列表(通常有 100+ 个)。
  4. 筛选
    • 排除用户显式 exclude 的类。
    • 利用 @Conditional 系列注解进行过滤(检查类路径有没有对应的 Jar 包、检查有没有用户自定义的 Bean、检查配置文件属性)。
  5. 注册:将筛选后剩下的、符合条件的配置类加载到 Spring IOC 容器中,这些配置类中定义的 @Bean 方法被执行,完成组件的自动装配。

一句话总结:
Spring Boot 启动时,通过 spring.factories (或 .imports) 获取所有自动配置类,然后利用 @Conditional 注解根据当前环境(类路径、已有 Bean、配置文件)动态决定哪些配置类生效,从而实现“即插即用”。

右滑查看面试常问