设计模式与Spring Boot:自动配置中的工厂、Starter中的外观、Actuator中的观察者
说实话,Spring Boot 能火起来,靠的不是什么黑魔法。它背后藏着一套设计模式的组合拳。我这些年看过的项目里,很多人会用 Spring Boot,但真要问起「自动配置为什么能自动?」「Starter 为什么加个依赖就能用?」「Actuator 怎么做到实时监控的?」——能讲清楚的不多。
今天咱们就掰开揉碎,聊聊这三个核心机制背后的设计模式。工厂、外观、观察者,这三个模式在 Spring Boot 里被用到了极致。
自动配置中的工厂模式
先问个问题:Spring Boot 启动时,那些 @ConditionalOnClass、@ConditionalOnMissingBean 是怎么工作的?
说白了,这就是一个工厂模式的变体。Spring Boot 内部维护了一个「自动配置候选列表」,启动时遍历这些候选类,判断条件是否满足,满足就创建 Bean。
核心思想:将对象的创建逻辑封装在配置类中,由条件注解决定是否「生产」这个对象。
我记得有一次排查一个项目启动慢的问题。翻日志发现,某个自动配置类加载了,但条件不满足,白白浪费了类加载时间。后来我建议团队在 spring.factories 里精简自动配置项,启动速度快了 30%。
来看一个简化版的自动配置工厂:
// 自动配置类,相当于工厂方法
@Configuration
@ConditionalOnClass(name = "com.example.SomeService")
public class SomeServiceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SomeService someService() {
return new SomeServiceImpl();
}
}
// spring.factories 中注册
// org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
// com.example.autoconfigure.SomeServiceAutoConfiguration
这里 SomeServiceAutoConfiguration 就是一个工厂。它根据条件决定是否生产 SomeService 实例。你想想看,如果没有这个模式,每个项目都得手动写一堆 @Bean,那 Spring Boot 还谈什么「开箱即用」?
避坑指南:我曾经在项目中遇到自动配置冲突的问题。两个 Starter 都试图创建同一个类型的 Bean,结果启动报错。解决方案是用 @ConditionalOnMissingBean 加上 @Order 控制优先级。
Starter 中的外观模式
Starter 是什么?说白了就是一个「打包好的依赖集合」。你加一个 spring-boot-starter-data-redis,Redis 的连接池、序列化器、模板类全都有了。
这背后就是外观模式。Starter 把一堆复杂的配置、依赖、Bean 定义全部封装起来,对外只暴露一个简单的坐标(GAV)。
我个人习惯在设计 Starter 时,遵循三个原则:
- 最小依赖原则:只引入必要的依赖,避免传递依赖污染
- 自动配置 + 手动覆盖:提供默认配置,但允许用户通过
application.yml覆盖 - 条件注解兜底:用
@ConditionalOnProperty控制开关
来看一个自定义 Starter 的结构:
my-starter/
├── pom.xml
├── src/main/java/com/example/starter/
│ ├── MyService.java // 核心服务接口
│ ├── MyServiceImpl.java // 默认实现
│ ├── MyProperties.java // 配置属性类
│ └── MyServiceAutoConfiguration.java // 自动配置
└── src/main/resources/
└── META-INF/
└── spring.factories // 注册自动配置
用户使用时只需要:
<dependency>
<groupId>com.example</groupId>
<artifactId>my-starter</artifactId>
<version>1.0.0</version>
</dependency>
就这一行,所有配置都到位了。这就是外观模式的魅力——把复杂性藏起来,给用户一个简单的入口。
注意:外观模式不是「万能胶」。我见过有人把整个业务逻辑都塞进 Starter 里,结果升级时牵一发动全身。Starter 只应该做「集成」和「配置」,不要包含业务代码。
Actuator 中的观察者模式
Actuator 是 Spring Boot 的监控模块。它怎么知道应用的健康状态?怎么收集指标数据?
答案是观察者模式。Actuator 内部维护了一组 HealthIndicator,每个 Indicator 都是一个观察者。当调用 /actuator/health 时,Actuator 会遍历所有 Indicator,收集它们的健康状态。
我画了一张图,帮你理解这个流程:
你看,HealthEndpoint 是主题,它不关心具体有哪些 Indicator。你加一个新的 HealthIndicator,它自动就能感知到。这就是观察者模式的核心——松耦合。
代码层面更简单:
// 自定义健康指标,自动被 Actuator 发现
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
boolean isHealthy = checkExternalService();
if (isHealthy) {
return Health.up().withDetail("service", "running").build();
}
return Health.down().withDetail("service", "unreachable").build();
}
private boolean checkExternalService() {
// 模拟检查
return true;
}
}
你只需要实现 HealthIndicator 接口,Spring Boot 会自动把它注册到观察者列表中。调用 /actuator/health 时,所有 Indicator 的结果会被聚合起来。
经验之谈:我曾经在微服务项目中,给每个服务都加了自定义的 HealthIndicator,用来检查下游依赖是否可用。这样网关层做负载均衡时,可以直接根据健康状态剔除故障节点。效果非常好。
三种模式的协同
这三种模式在 Spring Boot 里不是孤立的。它们互相配合,构成了一个完整的生态:
| 模式 | Spring Boot 中的角色 | 核心价值 |
|---|---|---|
| 工厂模式 | 自动配置(@Conditional 系列) | 按需创建 Bean,减少手动配置 |
| 外观模式 | Starter(spring-boot-starter-*) | 封装复杂依赖,提供统一入口 |
| 观察者模式 | Actuator(HealthIndicator、Metrics) | 松耦合收集状态,支持扩展 |
你想想看,如果没有工厂模式,自动配置就做不到「按需加载」;没有外观模式,Starter 就做不到「一键集成」;没有观察者模式,Actuator 就做不到「动态扩展」。
这三个模式,说白了就是 Spring Boot 的「三驾马车」。理解它们,你才算真正看懂了 Spring Boot 的设计哲学。
总结一下:工厂模式管「创建」,外观模式管「封装」,观察者模式管「通知」。下次面试官问你 Spring Boot 的设计模式,你就从这三个角度切入,保证能说到点子上。
公众号:蓝海资料掘金营,微信deep3321