Spring Boot 自动配置原理:从 @SpringBootApplication 到自定义 Starter

1. 引言

Spring Boot 之所以能让我们「开箱即用」,核心就在于它的自动配置机制。你只需要引入一个依赖,再写几行配置,框架就能自动帮你装配好所需的 Bean。这篇文章将带你从 @SpringBootApplication 出发,一步步拆解自动配置的底层原理,并手把手实现一个自定义 Starter。

2. @SpringBootApplication 拆解

@SpringBootApplication 是一个组合注解,它由以下三个核心注解组成:

java 复制代码
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
    @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {
}

2.1 @SpringBootConfiguration

它本质上是 @Configuration 的派生注解,表示当前类是一个配置类,Spring 容器会把它当作配置源来解析。

2.2 @ComponentScan

负责扫描当前包及其子包下的 @Component、@Service、@Repository 等注解,将它们注册为 Bean。注意它默认只扫描启动类所在的包,这也是为什么我们通常把启动类放在顶层包的原因。

2.3 @EnableAutoConfiguration

这是自动配置的入口,它通过 @Import(AutoConfigurationImportSelector.class) 引入了一个选择器,由后者去加载所有自动配置类。

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}

3. 条件装配 @Conditional

自动配置类并不会无条件生效,而是通过一系列 @Conditional 注解来决定是否装配。常见的条件注解包括:

注解 作用
@ConditionalOnClass 当类路径下存在指定类时才生效
@ConditionalOnMissingBean 当容器中不存在指定 Bean 时才生效
@ConditionalOnProperty 当配置文件中存在指定属性时才生效
@ConditionalOnWebApplication 当应用是 Web 应用时才生效

例如,RedisAutoConfiguration 只有在类路径下存在 RedisOperations 类时才会被加载:

java 复制代码
@AutoConfiguration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
}

这种「按需装配」的设计,既保证了功能的完整性,又避免了不必要的 Bean 创建。

4. spring.factories 与 AutoConfiguration.imports

4.1 早期的 spring.factories

在 Spring Boot 2.7 之前,自动配置类是通过 META-INF/spring.factories 文件来声明的:

properties 复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.starter.MyAutoConfiguration

4.2 新的 AutoConfiguration.imports

从 Spring Boot 2.7 开始,官方推荐使用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件,每行一个自动配置类的全限定名:

text 复制代码
com.example.starter.MyAutoConfiguration

新方式更简洁,也避免了 spring.factories 中大量无关配置的干扰。AutoConfigurationImportSelector 会读取这些文件,并经过条件判断后,将符合条件的配置类导入容器。

5. 自定义 Starter 示例

下面我们来实现一个简单的「问候语 Starter」,让使用者只需引入依赖即可获得一个 GreetingService。

5.1 创建自动配置类

java 复制代码
package com.example.greeting;

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

@AutoConfiguration
@ConditionalOnClass(GreetingService.class)
@EnableConfigurationProperties(GreetingProperties.class)
public class GreetingAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public GreetingService greetingService(GreetingProperties properties) {
        return new GreetingService(properties.getPrefix());
    }
}

5.2 定义属性类

java 复制代码
package com.example.greeting;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "greeting")
public class GreetingProperties {

    private String prefix = "Hello";

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }
}

5.3 声明自动配置类

在 src/main/resources/META-INF/spring/ 下创建文件 org.springframework.boot.autoconfigure.AutoConfiguration.imports:

text 复制代码
com.example.greeting.GreetingAutoConfiguration

5.4 使用 Starter

使用方只需在 pom.xml 中引入依赖,并在配置文件中指定前缀:

yaml 复制代码
greeting:
  prefix: "你好"

然后在代码中注入即可:

java 复制代码
@Autowired
private GreetingService greetingService;

public void sayHello() {
    System.out.println(greetingService.greet("Spring Boot"));
}

6. 总结

Spring Boot 的自动配置原理可以概括为三步:

  1. @EnableAutoConfiguration 通过 AutoConfigurationImportSelector 加载自动配置类;
  2. 自动配置类通过 @Conditional 系列注解按需装配;
  3. 自动配置类的声明从 spring.factories 演进为 AutoConfiguration.imports。

理解这套机制后,你不仅能更好地排查配置问题,还能像 Spring 官方一样,写出属于自己的 Starter。

相关推荐
码事漫谈7 小时前
黄仁勋被裁第一天,就收到了橄榄枝
后端
金銀銅鐵8 小时前
带您看懂字节码指令(二):空循环里有什么
java·后端·ai编程
皮皮林5519 小时前
比 Xshell 还好用的 SSH 客户端神器,MobaXterm 太爱了!
后端
吴名氏.10 小时前
Java转AI Agent教程(第十三周)混合检索与重排
java·数据库·人工智能·ai·ai agent
我不会起名字32210 小时前
会话缓存失效排查:区分 Redis 失效与节点广播
redis·后端·go·即时通讯·im·故障排查
.痞老板.10 小时前
java ee--多线程(进阶)
java·java-ee
深入云栈12 小时前
Netty 4.2.x 源码深度解析 (二十三):ByteBuf 核心设计 —— 索引、类型与零拷贝
java·后端·架构
JackJiang12 小时前
IM踩坑:聊天消息ID怎么设计?一个UUID搞不定,我用双ID解决
后端·架构
Jackzhang12 小时前
[运维排障实录] 第一次遇到 502 别急着重启:按「一条线」把问题查清楚
spring boot
开心猴爷12 小时前
iOS 上架 App 流程
后端·ios