自动配置(对比 Service Provider)
Laravel 的每个功能通过 ServiceProvider 显式注册;Spring Boot 则发明了 「自动配置」(Auto-configuration):只要 classpath 里有某个依赖,Spring Boot 就自动帮你把这个功能的 Bean 装配好。这就是「Boot」二字的含义 —— 你只管依赖,配置它来搞定。
从 spring-boot-starter-web 看自动配置
你引入 spring-boot-starter-web 之后,什么都没配置,Tomcat 就启动、Spring MVC 就能用、JSON 序列化就好使。这些是谁干的?
Spring Boot 在 spring-boot-autoconfigure 包里,对常见的「功能场景」各自准备了一个「自动配置类」。以 Web 为例,它自动做了:
| 功能 | 自动配置类帮你做的事 | Laravel 需要手动做的 |
|---|---|---|
| 内嵌 Tomcat | 启动 Tomcat | 配 Nginx/PHP-FPM |
| JSON 序列化 | 自动发现 classpath 里的 Jackson | 手动引入依赖 |
| 静态资源 | 把 /static/ 映射为 / 可访问 | 放 public/ 目录即可 |
| 错误页 | 默认错误 JSON | 手动写 404 页 |
| 消息转换 | 根据 Content-Type 自动选择转换器 | 手动处理 |
为什么能自动:条件装配 @ConditionalOnXxx
自动配置不是「无脑全部开启」,而是「满足条件才开启」。靠的是 @ConditionalOnXxx 系列注解,常见的有:
| 注解 | 条件 | 场景 |
|---|---|---|
@ConditionalOnClass | classpath 里有某个类 | 有 H2 依赖才配置 H2 |
@ConditionalOnMissingBean | 容器里还没有某个 Bean | 用户自定义了就不覆盖 |
@ConditionalOnProperty | 某个配置项的值 | spring.jpa.hibernate.ddl-auto 有值才生效 |
@ConditionalOnWebApplication | 是 Web 应用 | 非 Web 应用不加载 Web 配置 |
这就是自动配置「智能」的来源:它给了你覆盖的机会。你自定义了一个 DataSource Bean,Spring 就通过 @ConditionalOnMissingBean 跳过默认的。
一句话总结
自动配置 = 内置了一堆「如果没被用户自定义就自动装配」的默认 Bean。它不是魔法,是条件判断 + 约定。
自动配置的三大「开关」
1. 主开关 @SpringBootApplication
这个注解 = 三个注解的合体:
| 组成注解 | 作用 |
|---|---|
@SpringBootConfiguration | 标记这是配置类 |
@EnableAutoConfiguration | 开启自动配置(灵魂) |
@ComponentScan | 扫描当前包及其子包的 @Component 等 |
对应到 Laravel:@ComponentScan 约等于「自动加载 app/ 目录下的类」,@EnableAutoConfiguration 约等于「自动注册所有 ServiceProvider」的开关。
2. 排除某个自动配置
某个功能自动装配和你想要的不一致时,可以排除:
@SpringBootApplication(exclude = {
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.class
})
public class DemoApplication { ... }或者在配置里:
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration3. 调试开关
想知道哪些自动配置生效了/没生效:
debug: true启动日志会打印一份「Positive matches / Negative matches」报告,非常有用。
自己写一个自动配置(理解原理)
把流程走一遍你就彻底懂了。假设做一个小工具包:graceful-request-id,给每个请求分配一个 ID。
第 1 步:写配置属性类
@ConfigurationProperties(prefix = "graceful")
@Data
public class GracefulProperties {
private boolean enabled = true;
private String headerName = "X-Request-Id";
}第 2 步:写自动配置类
@AutoConfiguration
@EnableConfigurationProperties(GracefulProperties.class)
@ConditionalOnWebApplication
public class GracefulAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "graceful", name = "enabled", havingValue = "true", matchIfMissing = true)
public RequestIdFilter requestIdFilter(GracefulProperties props) {
return new RequestIdFilter(props);
}
}第 3 步:注册进 META-INF/spring/...AutoConfiguration.imports
在 src/main/resources/META-INF/spring/ 下建文件:
org.springframework.boot.autoconfigure.AutoConfiguration.imports内容一行:
com.example.graceful.GracefulAutoConfiguration然后任何项目引入你这个 jar,只要条件满足,就自动获得请求 ID 功能。
类比 Laravel 包开发
Laravel 包在 composer.json 的 extra.laravel.providers 里注册 ServiceProvider;Spring Boot 包在这个 .imports 文件里注册自动配置类。位置不同,思想一样:让使用方零配置。
自动配置与 ServiceProvider 的对比
| 维度 | Laravel ServiceProvider | Spring Boot 自动配置 |
|---|---|---|
| 触发时机 | 显式注册后加载 | 依赖在 classpath 中自动加载 |
| 是否条件化 | 基本不 | 大量 @ConditionalOnXxx |
| 覆盖方式 | 改绑定的实现 | 自定义 Bean 即覆盖(@ConditionalOnMissingBean) |
| 心智负担 | 手动,清晰 | 自动,隐藏,但可查可排 |
两个坑
- 入口类位置:
@SpringBootApplication的扫描范围是「所在包及子包」。组件放错包 → 扫不到 → 启动报错或注入 null。 - 依赖冲突:自动配置依赖 classpath 判断,重复引入不同版本 starter 可能出现诡异行为。用 IDEA 的 Maven 面板查看依赖树排查。
查看实际生效的配置
debug: true看 Positive/Negative matches 报告- 启动日志搜
Started DemoApplication前的那段Auto-configuration report - 加
spring-boot-starter-actuator后访问/actuator/conditions实时查看
理解完自动配置,你就真正理解了「Spring Boot 为什么能少写那么多配置」。接下来,搞懂这一切的语法基础:注解机制:为什么用注解。