1. Spring Boot设计模式概述
在Java企业级开发领域,设计模式是解决特定问题的经典方案。Spring Boot作为Spring框架的"约定优于配置"实现,其内部大量运用了各种设计模式来简化开发流程。这些模式不是凭空出现的,而是Spring框架在长期演进过程中,为解决特定场景下的问题而逐步引入的最佳实践。
我曾在多个Spring Boot项目中观察到,许多开发者虽然熟练使用框架功能,但对底层设计模式的理解往往停留在表面。这种认知断层会导致两个问题:一是遇到复杂需求时缺乏模式化思维,二是无法充分利用框架提供的扩展点。本文将系统梳理Spring Boot中九种最经典的设计模式实现,包括它们的应用场景、实现方式以及实际案例。
2. 工厂模式在Spring Boot中的应用
2.1 BeanFactory与ApplicationContext
Spring框架的核心就是一个超级工厂,BeanFactory接口定义了最基本的工厂行为。在Spring Boot中,我们更常用的是它的子接口ApplicationContext。这个工厂模式的特殊之处在于:
- 它生产的是Spring管理的Bean对象
- 工厂本身也是被管理的Bean
- 支持多种Bean定义方式(注解、XML、Java配置)
java复制// 典型的工厂方法使用示例
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
}
2.2 工厂模式的进阶应用
Spring Boot自动配置大量使用了工厂模式。比如DataSourceAutoConfiguration中,它会根据classpath中存在的数据库驱动类,动态创建合适的数据源实现。这种"运行时决策"的特性正是工厂模式的精髓所在。
实际经验:在自定义starter开发时,应该优先考虑工厂模式。比如根据不同的环境参数返回不同的服务实现,这种场景使用@Conditional系列注解配合@Bean方法会非常优雅。
3. 单例模式:Spring Bean的默认作用域
3.1 单例模式的核心实现
Spring默认将所有Bean配置为单例,这是通过SingletonBeanRegistry接口实现的。与传统的单例实现不同,Spring的单例:
- 不是类级别的单例,而是应用上下文级别的单例
- 支持延迟初始化
- 线程安全由Spring保障
java复制@Service
public class OrderService {
// 这个服务在Spring容器中默认是单例的
}
3.2 单例模式的注意事项
在微服务架构下,单例Bean的使用需要特别注意:
- 避免在单例Bean中保存状态信息
- 依赖注入的Bean默认也是单例的
- 与@Scope("prototype")的Bean混用时要注意生命周期差异
我曾经在一个电商项目中遇到缓存污染问题,就是因为误将带有状态的工具类配置成了单例。解决方案是改用@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)。
4. 代理模式:AOP的基石
4.1 JDK动态代理与CGLIB
Spring AOP的实现基于代理模式,根据目标类是否实现接口,Spring会选择不同的代理策略:
- JDK动态代理:基于接口,使用Proxy.newProxyInstance
- CGLIB:基于类继承,生成子类代理
java复制@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logMethodCall(ProceedingJoinPoint joinPoint) throws Throwable {
// 前置逻辑
Object result = joinPoint.proceed();
// 后置逻辑
return result;
}
}
4.2 代理模式的实际应用
在Spring Boot中,代理模式随处可见:
- @Transactional的事务管理
- @Cacheable的缓存处理
- @Retryable的重试机制
- Spring Security的方法安全
性能提示:CGLIB代理的性能略低于JDK动态代理,但在Spring Boot 2.0之后,这个差距已经大幅缩小。如果不需要接口的灵活性,可以直接使用类级别的代理。
5. 模板方法模式:JdbcTemplate等模板类的核心
5.1 模板方法的Spring实现
Spring提供了多种模板类来简化重复性操作:
- JdbcTemplate:数据库操作
- RestTemplate:HTTP调用
- JmsTemplate:消息队列
- TransactionTemplate:事务管理
这些模板类都遵循相同的模式:定义算法骨架,将可变部分延迟到子类或回调接口。
java复制jdbcTemplate.execute("SELECT * FROM users", (PreparedStatement ps) -> {
// 这里是可变部分的具体实现
ResultSet rs = ps.executeQuery();
// 处理结果集
return null;
});
5.2 自定义模板方法实践
在支付网关集成项目中,我抽象出一个通用的支付模板:
java复制public abstract class PaymentTemplate {
// 模板方法定义为final防止子类修改
public final PaymentResult process(PaymentRequest request) {
validate(request);
preProcess(request);
PaymentResponse response = execute(request);
return postProcess(response);
}
protected abstract PaymentResponse execute(PaymentRequest request);
// 其他钩子方法...
}
这种模式特别适合有固定流程但实现各异的业务场景,如不同支付渠道的对接。
6. 观察者模式:Spring事件机制
6.1 ApplicationEvent体系
Spring的事件机制是观察者模式的典型实现:
- ApplicationEvent:事件基类
- ApplicationListener:观察者接口
- ApplicationEventPublisher:事件发布者
java复制// 自定义事件
public class OrderCompletedEvent extends ApplicationEvent {
public OrderCompletedEvent(Order source) {
super(source);
}
}
// 事件监听器
@Component
public class OrderEventListener {
@EventListener
public void handleOrderCompleted(OrderCompletedEvent event) {
// 处理订单完成事件
}
}
6.2 异步事件处理
在Spring Boot中,可以通过@Async实现异步事件处理:
java复制@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.initialize();
return executor;
}
}
// 使用示例
@Async
@EventListener
public void handleAsyncEvent(OrderCompletedEvent event) {
// 异步处理逻辑
}
经验之谈:事件机制非常适合解耦核心业务与非核心业务。比如订单完成后发送通知、更新统计数据等操作,都可以通过事件机制异步处理,避免影响主流程性能。
7. 适配器模式:Spring MVC的核心
7.1 HandlerAdapter的实现
Spring MVC中,DispatcherServlet并不直接处理请求,而是通过HandlerAdapter接口将不同类型的处理器适配成统一调用方式。常见的适配器包括:
- RequestMappingHandlerAdapter:处理@RequestMapping注解的方法
- SimpleControllerHandlerAdapter:处理Controller接口的实现
- HttpRequestHandlerAdapter:处理HttpRequestHandler接口的实现
java复制// 自定义适配器示例
public class CustomHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof CustomController;
}
@Override
public ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
CustomController controller = (CustomController) handler;
return controller.process(request, response);
}
// 其他方法实现...
}
7.2 适配器模式的实际价值
在老旧系统迁移项目中,适配器模式发挥了巨大作用。我们通过自定义适配器,逐步将Struts 1.x的Action逐步迁移到Spring MVC,实现了平滑过渡:
- 第一阶段:StrutsActionAdapter适配原有Action
- 第二阶段:混合使用新旧控制器
- 第三阶段:完全迁移到@Controller
这种渐进式重构避免了"一刀切"带来的风险,特别适合业务复杂的系统。
8. 装饰器模式:Spring Cache的实现原理
8.1 CacheManager的装饰链
Spring Cache抽象使用了装饰器模式来增强缓存功能:
- 基础实现:ConcurrentMapCacheManager
- 事务支持:TransactionAwareCacheManagerProxy
- 缓存统计:CacheStatisticsManager
java复制@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
// 装饰为支持事务的CacheManager
return new TransactionAwareCacheManagerProxy(cacheManager);
}
}
8.2 自定义装饰器实践
在统一缓存监控需求中,我实现了一个统计装饰器:
java复制public class MetricsCacheManagerDecorator implements CacheManager {
private final CacheManager delegate;
private final CacheMetrics metrics;
public MetricsCacheManagerDecorator(CacheManager delegate) {
this.delegate = delegate;
this.metrics = new CacheMetrics();
}
@Override
public Cache getCache(String name) {
Cache cache = delegate.getCache(name);
return new MetricsCacheDecorator(cache, metrics);
}
// 其他方法...
}
这种设计可以在不修改原有代码的情况下,为缓存系统添加监控指标,完美符合开闭原则。
9. 策略模式:Spring Security的认证策略
9.1 AuthenticationManager的策略实现
Spring Security的认证过程是策略模式的经典案例:
- ProviderManager:认证策略管理器
- AuthenticationProvider:认证策略接口
- 多种实现:DaoAuthenticationProvider、JwtAuthenticationProvider等
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public AuthenticationManager authManager(
List<AuthenticationProvider> providers) {
return new ProviderManager(providers);
}
@Bean
public AuthenticationProvider daoAuthProvider(
PasswordEncoder encoder,
UserDetailsService userDetailsService) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(encoder);
provider.setUserDetailsService(userDetailsService);
return provider;
}
}
9.2 自定义认证策略
在OAuth2资源服务器项目中,我们需要同时支持JWT和OPAQUE两种令牌:
java复制public class DualTokenAuthenticationProvider implements AuthenticationProvider {
private final JwtAuthenticationProvider jwtProvider;
private final OpaqueTokenAuthenticationProvider opaqueProvider;
@Override
public Authentication authenticate(Authentication authentication) {
String token = (String) authentication.getCredentials();
if (isJwt(token)) {
return jwtProvider.authenticate(authentication);
} else {
return opaqueProvider.authenticate(authentication);
}
}
private boolean isJwt(String token) {
// 简单的JWT识别逻辑
return token.countMatches('.') == 2;
}
}
这种策略组合方式既保持了扩展性,又对外提供了统一的认证接口。
10. 组合模式:Spring WebFlux的函数式端点
10.1 RouterFunction的组合特性
Spring WebFlux引入了函数式编程模型,其中RouterFunction的实现采用了组合模式:
- 单个路由:RouterFunctions.route()
- 路由组合:and()、andOther()、andRoute()
- 嵌套路由:nest()
java复制@Bean
public RouterFunction<ServerResponse> productRoutes(ProductHandler handler) {
return route()
.GET("/products", handler::listProducts)
.POST("/products", handler::createProduct)
.nest(RequestPredicates.path("/products/{id}"), builder ->
builder
.GET(handler::getProduct)
.PUT(handler::updateProduct)
.DELETE(handler::deleteProduct)
)
.build();
}
10.2 组合模式的优势
在API网关开发中,组合模式让我们可以模块化地构建路由规则:
- 按业务领域拆分路由定义
- 动态组合不同来源的路由配置
- 统一添加全局过滤器(如认证、日志)
java复制@Bean
public RouterFunction<ServerResponse> compositeRoutes(
UserRoutes userRoutes,
OrderRoutes orderRoutes,
AuthFilter authFilter) {
return userRoutes.routes()
.andOther(orderRoutes.routes())
.filter(authFilter::apply);
}
这种结构特别适合微服务架构下的路由管理,每个团队可以维护自己的路由配置,然后在网关层统一组合。
11. 设计模式综合应用实践
11.1 电商订单系统案例
在一个真实的电商项目中,我们综合运用了多种设计模式:
- 工厂模式:创建不同的支付处理器
- 策略模式:计算运费和折扣
- 观察者模式:订单状态变更通知
- 模板方法:订单处理流程
- 装饰器模式:添加缓存和日志
java复制@Service
@RequiredArgsConstructor
public class OrderService {
private final PaymentProcessorFactory factory;
private final List<OrderObserver> observers;
private final OrderTemplate orderTemplate;
@Transactional
public OrderResult createOrder(OrderRequest request) {
Order order = orderTemplate.process(request);
PaymentProcessor processor = factory.create(request.getPaymentType());
PaymentResult result = processor.process(order);
observers.forEach(observer ->
observer.onOrderCreated(new OrderEvent(order)));
return convertToResult(order, result);
}
}
11.2 性能优化经验
在设计模式使用过程中,我们总结出一些性能优化经验:
- 单例Bean要特别注意线程安全问题
- 代理模式会增加调用栈深度,影响性能
- 事件机制要合理配置线程池
- 装饰器链不宜过长
- 策略枚举比动态创建策略实例更高效
在某个高并发场景下,我们将策略模式的实现从动态实例化改为枚举常量,性能提升了约15%:
java复制public enum ShippingStrategy {
STANDARD {
public BigDecimal calculate(Order order) {
// 标准运费计算
}
},
EXPRESS {
public BigDecimal calculate(Order order) {
// 快递运费计算
}
};
public abstract BigDecimal calculate(Order order);
}
12. Spring Boot设计模式学习建议
12.1 源码阅读指南
要深入理解Spring Boot中的设计模式,源码阅读是必不可少的。我推荐从这些类入手:
- AbstractApplicationContext:工厂模式和模板方法
- DefaultAopProxyFactory:代理模式
- AbstractAutowireCapableBeanFactory:单例模式
- EventListenerMethodProcessor:观察者模式
- WebMvcConfigurationSupport:适配器模式
阅读技巧:
- 先看类图,了解整体结构
- 关注设计模式相关的接口和抽象类
- 使用IDE的继承层次查看功能
- 配合调试理解运行时行为
12.2 实践项目建议
为了巩固设计模式的理解,可以尝试这些实践:
- 实现一个简单的IoC容器
- 基于事件机制构建通知系统
- 开发自定义Spring Starter
- 为现有功能添加AOP支持
- 实现可插拔的权限策略
我在团队内部推行过"设计模式发现周"活动,每周聚焦一个模式,鼓励大家在Spring源码中寻找实例并分享。这种刻意练习显著提升了团队的设计能力。
