1. 设计模式与Spring框架的共生关系
在Java生态中,Spring框架与设计模式的关系就像咖啡与咖啡机——前者提供理论基础,后者实现自动化生产。我从业十余年见证过太多项目从混乱走向优雅,其中设计模式的正确应用往往是转折点。Spring框架本质上是一个设计模式的实现库,它的IoC容器是工厂模式的集大成者,AOP模块则是代理模式的典范,而MVC架构则完美诠释了前端控制器模式。
为什么Spring要大量采用设计模式?这得从框架设计的根本目标说起。框架存在的意义是提供可复用的架构解决方案,而设计模式恰好是经过验证的最佳实践。当你在Spring中@Autowired一个依赖时,背后是工厂模式在管理对象生命周期;当你在Controller上写@RequestMapping时,前端控制器模式正在路由你的请求;当你使用@Transactional时,代理模式正在为你处理事务边界。
关键认知:Spring不是设计模式的简单堆砌,而是对其进行了符合JavaEE特性的改造。比如模板方法模式在JDBC抽象层中的应用,就考虑了连接池管理、异常转换等实际场景。
2. 模板方法模式在Spring中的经典实现
2.1 JdbcTemplate的模板方法实践
打开Spring的JdbcTemplate源码,你会看到教科书级的模板方法实现。以query()方法为例,它定义了执行SQL的固定流程:获取连接->创建语句->设置参数->执行查询->处理结果集->释放资源。而可变部分(如结果集处理)通过RowMapper接口开放给开发者。
java复制public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
return query(sql, new RowMapperResultSetExtractor<>(rowMapper));
}
// 实际执行流程(模板方法):
1. Connection con = DataSourceUtils.getConnection(getDataSource());
2. Statement stmt = con.createStatement();
3. ResultSet rs = stmt.executeQuery(sql);
4. while (rs.next()) {
result.add(rowMapper.mapRow(rs, rowNumber++));
}
5. JdbcUtils.closeResultSet(rs);
6. JdbcUtils.closeStatement(stmt);
7. DataSourceUtils.releaseConnection(con, getDataSource());
这种设计带来的好处是:开发者只需关注业务逻辑(RowMapper实现),而不用重复编写资源管理代码。我在金融项目中处理复杂报表查询时,通过自定义RowMapper将数据库记录转为领域对象,代码量减少了40%且完全消除了资源泄漏问题。
2.2 事务管理的模板模式
Spring事务抽象层同样采用模板方法模式。AbstractPlatformTransactionManager定义了标准事务流程:
code复制1. 获取事务状态
2. 执行前检查
3. 开启事务
|- 4. 执行业务逻辑
5. 提交/回滚
6. 清理资源
不同数据库厂商只需实现doBegin()、doCommit()等抽象方法即可接入Spring事务体系。我曾为MongoDB实现过自定义事务管理器,发现模板方法模式使得非关系型数据库也能复用Spring的事务注解体系。
避坑指南:继承Spring模板类时,务必区分哪些方法可以重写(通常有@Overrid注解),哪些是内部final方法。错误覆盖可能导致事务不生效等隐蔽问题。
3. 工厂模式在Spring IoC容器的核心地位
3.1 BeanFactory与FactoryBean的双重工厂
Spring容器本身就是个超级工厂,但它的工厂实现分为两个层次:
- BeanFactory:基础工厂接口,定义了getBean()等核心方法
- FactoryBean:特殊工厂接口,用于创建复杂对象
java复制// 典型FactoryBean实现(以MyBatis的SqlSessionFactoryBean为例)
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory> {
private DataSource dataSource;
public SqlSessionFactory getObject() {
return new SqlSessionFactoryBuilder().build(configuration);
}
public Class<?> getObjectType() {
return SqlSessionFactory.class;
}
}
在电商项目中,我们曾用FactoryBean动态生成不同商家的支付接口代理。通过将商家编号作为参数注入FactoryBean,实现了支付接口的运行时按需创建。
3.2 @Configuration的工厂方法模式
Spring JavaConfig是工厂方法模式的现代演绎。@Bean注解的方法本质上就是静态工厂方法:
java复制@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource(config);
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
这种声明式工厂的优势在于:
- 方法参数自动装配解决了依赖问题
- 默认单例模式避免重复创建
- 结合@Profile可实现环境差异化配置
我在微服务实践中发现,将第三方SDK的初始化逻辑封装到@Bean方法中,能显著提升配置的可维护性。
4. 适配器模式在Spring MVC中的关键作用
4.1 HandlerAdapter的架构价值
Spring MVC最精妙的设计之一就是HandlerAdapter接口,它解决了不同类型Controller的统一调用问题。常见的适配器实现包括:
- RequestMappingHandlerAdapter:处理@Controller注解的类
- SimpleControllerHandlerAdapter:处理实现Controller接口的类
- HttpRequestHandlerAdapter:处理HttpRequestHandler实现类
java复制// 适配器接口定义
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception;
}
在兼容老旧系统时,我曾编写过自定义HandlerAdapter来适配Struts1的Action,使得老代码能逐步迁移到Spring MVC而不需要重写。
4.2 Spring AOP中的适配器应用
Spring AOP使用适配器模式将不同类型的AOP联盟通知(Advice)适配到统一的拦截器接口:
java复制public interface AdvisorAdapter {
boolean supportsAdvice(Advice advice);
MethodInterceptor getInterceptor(Advisor advisor);
}
// 具体适配器示例(AfterReturningAdviceAdapter)
public class AfterReturningAdviceAdapter implements AdvisorAdapter {
public boolean supportsAdvice(Advice advice) {
return (advice instanceof AfterReturningAdvice);
}
public MethodInterceptor getInterceptor(Advisor advisor) {
return new AfterReturningAdviceInterceptor(
(AfterReturningAdvice) advisor.getAdvice());
}
}
这种设计使得Spring能同时支持自己定义的AOP注解和AspectJ等第三方AOP实现。在统一日志方案中,我们混合使用了@Aspect和MethodInterceptor,适配器模式让两者完美协作。
5. 其他设计模式在Spring中的典型应用
5.1 代理模式与AOP实现
Spring AOP的核心是JDK动态代理和CGLIB代理的组合应用。当目标实现接口时使用JDK代理,否则使用CGLIB:
java复制// 简化版的代理选择逻辑
public class DefaultAopProxyFactory implements AopProxyFactory {
public AopProxy createAopProxy(AdvisedSupport config) {
if (config.isOptimize() || config.isProxyTargetClass() ||
hasNoUserSuppliedProxyInterfaces(config)) {
return new CglibAopProxy(config);
}
return new JdkDynamicAopProxy(config);
}
}
在性能敏感场景中,我们通过@EnableAspectJAutoProxy(proxyTargetClass=true)强制使用CGLIB,避免了JDK代理的反射开销。
5.2 观察者模式与事件机制
Spring的事件发布模型是观察者模式的典型实现:
java复制// 自定义事件
public class OrderCompletedEvent extends ApplicationEvent {
private Order order;
public OrderCompletedEvent(Object source, Order order) {
super(source);
this.order = order;
}
}
// 事件监听器
@Component
public class InventoryListener {
@EventListener
public void handleOrderCompleted(OrderCompletedEvent event) {
// 更新库存逻辑
}
}
// 事件发布
applicationContext.publishEvent(new OrderCompletedEvent(this, order));
在分布式系统中,我们将本地事件与消息队列集成,实现了跨服务的最终一致性。
5.3 装饰器模式与Wrapper类
Spring大量使用装饰器模式增强对象功能,比如:
- TransactionAwareCacheDecorator:为缓存增加事务支持
- LazyConnectionDataSourceProxy:延迟获取数据库连接
- UserTransactionAdapter:将JTA事务适配为Spring事务接口
在数据源配置中,我们经常用装饰器实现读写分离:
java复制@Bean
public AbstractRoutingDataSource routingDataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource());
targetDataSources.put("slave", slaveDataSource());
AbstractRoutingDataSource ds = new AbstractRoutingDataSource() {
protected Object determineCurrentLookupKey() {
return TransactionSynchronizationManager.isCurrentTransactionReadOnly()
? "slave" : "master";
}
};
ds.setTargetDataSources(targetDataSources);
return ds;
}
6. 设计模式组合应用的实战案例
6.1 电商优惠券系统的模式组合
在优惠券计算场景中,我们综合运用了多种设计模式:
- 策略模式:定义CouponStrategy接口,实现满减、折扣等不同算法
- 工厂模式:通过CouponStrategyFactory根据券类型创建对应策略
- 责任链模式:多个优惠券按优先级组成处理链
- 装饰器模式:使用CouponDecorator叠加运费优惠等附加条件
java复制// 策略接口
public interface CouponStrategy {
Order applyCoupon(Order order, Coupon coupon);
}
// 策略工厂
public class CouponStrategyFactory {
private Map<CouponType, CouponStrategy> strategies;
public CouponStrategy getStrategy(CouponType type) {
return strategies.get(type);
}
}
// 责任链应用
public class CouponChain {
private List<CouponStrategy> chain;
public Order applyAll(Order order) {
for (CouponStrategy strategy : chain) {
order = strategy.applyCoupon(order, order.getCoupon());
}
return order;
}
}
这种设计使得新增优惠类型只需实现新的CouponStrategy,符合开闭原则。在618大促期间,我们仅用2小时就接入了平台级跨店满减活动。
6.2 微服务网关中的模式应用
API网关是设计模式的集大成者:
- 过滤器链(责任链模式):认证、限流、日志等过滤器顺序执行
- 路由映射(策略模式):根据请求路径选择不同微服务实例
- 熔断器(状态机模式):在关闭、半开、打开状态间转换
- 配置加载(观察者模式):监听配置中心变更动态更新路由规则
java复制// 网关过滤器链示例
public interface GatewayFilter {
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
public class AuthFilter implements GatewayFilter {
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 认证逻辑
return chain.filter(exchange);
}
}
// 路由策略
public interface RoutePredicateFactory {
Predicate<ServerWebExchange> apply(Config config);
}
public class PathRoutePredicateFactory implements RoutePredicateFactory {
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
String path = exchange.getRequest().getPath().toString();
return path.startsWith(config.getPrefix());
};
}
}
在物联网平台网关开发中,这种模式组合使QPS提升了3倍,同时降低了80%的代码重复率。
7. Spring Boot自动配置的设计模式解析
7.1 条件化配置的策略模式
Spring Boot的@Conditional系列注解本质上是策略模式的应用:
java复制@Configuration
@ConditionalOnClass(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.enable", havingValue = "true")
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource() {
return new HikariDataSource();
}
}
每个@Conditional注解对应一个Condition策略实现:
java复制public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
// 类存在条件
public class OnClassCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String[] classes = getConditionClasses(metadata);
return ClassUtils.isPresent(classes[0], context.getClassLoader());
}
}
7.2 自动配置的工厂方法模式
Spring Boot Starter机制实际上是工厂方法模式的升级版。每个Starter提供一个或多个@Configuration类,通过META-INF/spring.factories注册:
code复制org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration
这种设计使得:
- 组件可以"即插即用"
- 配置逻辑封装在Starter内部
- 用户可以通过application.properties微调
在开发内部中间件时,我们将SDK、Spring配置、监控接入打包成Starter,使其他团队能一键接入完整功能。
