前言

作为一名有多年开发经验的老司机,每次翻看Spring源码都让我感叹:"这哪是框架,分明是设计模式的百科全书!"

有些小伙伴在工作中可能只会用@Autowired,却不知背后藏着多少精妙设计。

今天这篇文章跟大家一起聊聊Spring中最常用的10种设计模式,希望对你会有所帮助。

1 模板方法模式:流程骨架大师

场景:处理重复流程但允许细节变化

Spring应用JdbcTemplateRestTemplate

// 伪代码展示模板方法核心
public abstract class JdbcTemplate {
// 定义算法骨架(不可重写)
public final Object execute(String sql) {
Connection conn = getConnection(); // 抽象方法
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
Object result = mapResult(rs); // 抽象方法
releaseResources(conn, stmt, rs);
return result;
} // 留给子类实现的钩子方法
protected abstract Connection getConnection();
protected abstract Object mapResult(ResultSet rs);
}

为什么用

  1. 复用资源管理(连接获取/释放)等通用逻辑
  2. 允许子类只关注业务差异(如结果映射)

    思考:当你写重复流程时,想想能否抽出模板骨架

2 工厂模式:对象出生管理局

场景:解耦对象创建与使用

Spring应用BeanFactory核心接口

public interface BeanFactory {
Object getBean(String name);
<T> T getBean(Class<T> requiredType);
} // 实现类:DefaultListableBeanFactory
public class UserService {
// 使用者无需关心Bean如何创建
@Autowired
private OrderService orderService;
}

设计精髓

  • 隐藏复杂的对象初始化过程(如循环依赖处理)
  • 统一管理对象生命周期(单例/原型等作用域)

    类比:就像点外卖不需要知道厨师怎么做菜

3 代理模式:隐形护卫

场景:无侵入增强对象功能

Spring应用:AOP动态代理

// JDK动态代理示例
public class LogProxy implements InvocationHandler {
private Object target; public Object createProxy(Object target) {
this.target = target;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) {
System.out.println("【日志】调用方法: " + method.getName());
return method.invoke(target, args); // 执行原方法
}
} // Spring中通过@Aspect实现类似功能
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logMethodCall(JoinPoint jp) {
System.out.println("调用方法: " + jp.getSignature().getName());
}
}

动态代理两板斧

  1. JDK代理:基于接口(要求目标类实现接口)
  2. CGLIB代理:基于继承(可代理普通类)

    价值:业务逻辑与横切关注点(日志/事务等)彻底解耦

4 单例模式:全局唯一指挥官

场景:减少资源消耗,保证全局一致性

Spring实现:Bean默认作用域

// 源码片段:AbstractBeanFactory
public Object getBean(String name) {
Object bean = getSingleton(name); // 先查缓存
if (bean == null) {
bean = createBean(name); // 不存在则创建
addSingleton(name, bean); // 放入缓存
}
return bean;
}

关键设计

  • 三级缓存解决循环依赖(singletonObjects, earlySingletonObjects, singletonFactories)
  • 并发安全通过synchronized+双重检查锁定实现

    警示:切忌在单例Bean中保存状态变量!

5 观察者模式:事件广播网

场景:解耦事件生产者和消费者

Spring应用ApplicationEvent机制

// 1. 定义事件
public class OrderCreatedEvent extends ApplicationEvent {
public OrderCreatedEvent(Order source) {
super(source);
}
} // 2. 发布事件
@Service
public class OrderService {
@Autowired ApplicationEventPublisher publisher; public void createOrder(Order order) {
// 业务逻辑...
publisher.publishEvent(new OrderCreatedEvent(order));
}
} // 3. 监听事件
@Component
public class EmailListener {
@EventListener
public void handleOrderEvent(OrderCreatedEvent event) {
// 发送邮件通知
}
}

优势

  • 事件源与监听器完全解耦
  • 支持异步处理(加@Async注解即可)

6 策略模式:算法切换器

场景:动态选择算法实现

Spring应用Resource资源加载

// 资源加载策略族
Resource res1 = new ClassPathResource("config.xml"); // 类路径策略
Resource res2 = new UrlResource("http://config.com");// 网络策略
Resource res3 = new FileSystemResource("/opt/config");// 文件系统策略 // 统一调用接口
InputStream is = res1.getInputStream();

源码设计亮点

  • Resource接口统一抽象
  • 通过ResourceLoader自动选择策略

    应用场景:支付方式切换(微信/支付宝/银联)

7 适配器模式:接口转换器

场景:兼容不兼容的接口

Spring应用:Spring MVC的HandlerAdapter

// 伪代码:处理多种Controller
public class RequestMappingHandlerAdapter implements HandlerAdapter { public boolean supports(Object handler) {
return handler instanceof Controller;
} public ModelAndView handle(HttpRequest req, HttpResponse res, Object handler) {
Controller controller = (Controller) handler;
return controller.handleRequest(req, res); // 统一适配调用
}
} // 实际Spring源码中处理了:
// 1. @Controller注解类 2. HttpRequestHandler 3. Servlet实现等

价值

  • 让DispatcherServlet无需关心Controller具体类型
  • 新增Controller类型只需扩展适配器

8 装饰器模式:功能增强包

场景:动态添加功能

Spring应用HttpServletRequest包装

// 典型应用:缓存请求体
ContentCachingRequestWrapper wrappedRequest =
new ContentCachingRequestWrapper(rawRequest); // 可在filter中多次读取body
byte[] body = wrappedRequest.getContentAsByteArray();

源码实现

public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
private ByteArrayOutputStream cachedContent; @Override
public ServletInputStream getInputStream() {
// 装饰原方法:缓存流数据
}
}

设计本质:通过包装器在不修改原对象基础上增强功能

9 建造者模式:复杂对象组装工

场景:分步构建复杂对象

Spring应用BeanDefinitionBuilder

// 构建复杂的Bean定义
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserService.class);
builder.addPropertyValue("maxRetry", 3);
builder.setInitMethodName("init");
builder.setScope(BeanDefinition.SCOPE_SINGLETON); // 注册到容器
registry.registerBeanDefinition("userService", builder.getBeanDefinition());

对比传统构造

  • 解决多参数构造的混乱(尤其可选参数多时)
  • 构建过程更加清晰可读

10 责任链模式:拦截器的骨架设计

场景:解耦多步骤处理流程

Spring应用HandlerInterceptor拦截器链

// Spring MVC核心执行链
public class HandlerExecutionChain {
private final List<HandlerInterceptor> interceptors = new ArrayList<>(); // 执行前置处理(责任链核心)
public boolean applyPreHandle(HttpServletRequest request,
HttpServletResponse response) {
for (int i = 0; i < interceptors.size(); i++) {
HandlerInterceptor interceptor = interceptors.get(i);
// 任意拦截器返回false则中断链条
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, i); // 清理已完成
return false;
}
}
return true;
}
}

实战配置

@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 构建责任链
registry.addInterceptor(new LogInterceptor()).order(1);
registry.addInterceptor(new AuthInterceptor()).order(2);
registry.addInterceptor(new RateLimitInterceptor()).order(3);
}
} // 独立拦截器实现
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
if (!checkToken(req.getHeader("Authorization"))) {
res.sendError(401); // 认证失败
return false; // 中断链
}
return true; // 放行
}
}

设计价值

  1. 开闭原则:新增拦截器无需修改现有代码
  2. 单一职责:每个拦截器只关注单一功能
  3. 动态编排:通过order()灵活调整执行顺序
  4. 流程控制:任意节点可中断或继续传递

典型反模式:在拦截器中注入其他拦截器,这将破坏责任链独立性,导致循环依赖!

总结

  1. 解耦的艺术

    工厂模式解耦创建/使用,观察者模式解耦事件/处理

  2. 扩展性的智慧

    策略模式支持算法扩展,装饰器模式支持功能扩展

  3. 复杂性的封装

    模板方法封装流程,建造者模式封装构建

  4. 性能的权衡

    单例模式减少资源消耗,代理模式按需增强

最后送给小伙伴们的建议:不要为了用模式而用模式

就像Spring的作者Rod Johnson说的:"优雅的代码不是模式的堆砌,而是恰到好处的抽象。"

当你下次写代码感到别扭时,不妨想想这些经典模式,或许能豁然开朗。

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下我的同名公众号:苏三说技术,我的所有文章都会在公众号上首发,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

关注公众号:【苏三说技术】,在公众号中回复:进大厂,可以免费获取我最近整理的10万字的面试宝典,好多小伙伴靠这个宝典拿到了多家大厂的offer。

Spring用到的10种设计模式,真巧妙!的更多相关文章

  1. Spring主要用到两种设计模式

    Spring主要用到两种设计模式 1.工厂模式 Spring容器就是实例化和管理全部Bean的工厂. 工厂模式可以将Java对象的调用者从被调用者的实现逻辑中分离出来. 调用者只关心被调用者必须满足的 ...

  2. 初探Java设计模式5:一文了解Spring涉及到的9种设计模式

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  3. 深入解析spring中用到的九种设计模式

    转载请注明出处,文章首发于:http://itxxz.com/a/javashili/tuozhan/2014/0601/7.html 设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也 ...

  4. 初探设计模式5:Spring涉及到的9种设计模式

    设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆. 今天,螃蟹在IT学习者网站就设计模式的内在价值做一番探讨,并以spring为例进行讲解,只有领略了 ...

  5. 10 种保护 Spring Boot 应用的绝佳方法

    原文:developer.okta.com/blog/2018/07/30/10-ways-to-secure-spring-boot 译文:www.jdon.com/49653 Spring Boo ...

  6. Spring 实现两种设计模式:工厂模式和单态模式(单例模式)

    本文摘自:李刚 著 <轻量级 Java EE企业应用实战 Struts2+Spring+hibernate整合开发> 在Spring 中大量使用的以下两种设计模式:工厂模式和单态模式. 工 ...

  7. [转] 9种设计模式在Spring中的运用

    作者:iCoding91地址:https://blog.csdn.net/caoxiaohong1005 转发的公众号地址,有其他设计模式介绍:https://mp.weixin.qq.com/s/Z ...

  8. 9种设计模式在Spring中的运用,一定要非常熟练

    1.简单工厂(非23种设计模式中的一种) 实现方式: BeanFactory.Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数 ...

  9. 23种设计模式之自定义Spring框架(五)

    7,自定义Spring框架 7.1 spring使用回顾 自定义spring框架前,先回顾一下spring框架的使用,从而分析spring的核心,并对核心功能进行模拟. 数据访问层.定义UserDao ...

  10. Java开发中的23种设计模式详解

    [放弃了原文访问者模式的Demo,自己写了一个新使用场景的Demo,加上了自己的理解] [源码地址:https://github.com/leon66666/DesignPattern] 一.设计模式 ...

随机推荐

  1. 基于pandas的数据清洗 -- 缺失值(空值)的清洗

    博客地址:https://www.cnblogs.com/zylyehuo/ 开发环境 anaconda 集成环境:集成好了数据分析和机器学习中所需要的全部环境 安装目录不可以有中文和特殊符号 jup ...

  2. ShardingSphere分组聚合,数据异常问题

    在使用ShardingSphere分组聚合时是,出现了数据汇总不正确问题.我这里只进行了分表,未进行分库.使用的是广播查询,因为是定时任务统计,无法使用到分片键.进行分组的字段是两个 1. SQL查询 ...

  3. BUUCTF---萌萌哒的八戒(猪圈密码)

    1. 问题 2.知识点 猪圈密码 3.解题 对应解题,套上flag{whenthepigwanttoeat}

  4. 强化学习(on-policy)同步并行采样(on-line)的并行化效率分析

    在强化学习中(on-line)的算法如果是on-policy的算法都是需要较大的采样样本的,因此采样的效率往往对整个算法运行效率有着自关重要的影响,在deepmind(Google)公司的强化学习的并 ...

  5. 老生再谈 IoC

    IoC,Spring的核心理念之一,确实这是一个老生常谈的东西.但是今天呢!又重新温习之后,想再说说自己对IOC的一些想法. IoC--Inversion of Control,控制反转.要想理解Io ...

  6. Jmeter参数化总结

    参数化步骤: 1.连接数据库 2.获取account表手机号数据 3.获取手机号个数 4.增加For Each控制器 5.将请求添加至循环控制器里面 脚本:循环登录.jmx 页面如下: 下面主要说明F ...

  7. Bean注入几种方式 (放入Spring容器)

    目录 1.XML方式注入 set方式注入 构造方法注入 2.注解方式注入 @Component + @ComponentScan @Configuration + @Bean + @Component ...

  8. 什么是 MySQL 的主从同步机制?它是如何实现的?

    什么是 MySQL 的主从同步机制?它是如何实现的? MySQL 的主从同步机制是一种将主数据库(Master)上的数据实时或接近实时地同步到从数据库(Slave)的机制.通过这种机制,从数据库可以获 ...

  9. 如何在 MySQL 中实现读写分离?

    如何在 MySQL 中实现读写分离? 在 MySQL 中实现读写分离主要目的是为了提升数据库的性能和扩展性,将读请求和写请求分配到不同的服务器上,减轻主数据库的压力.通常,写请求会发送到主库,而读请求 ...

  10. MVVM_UI和逻辑分离(事件利用命令替换),命令代替事件,命令传递事件参数,附完整demo

    近期公司重构了些界面,因为换肤和界面定制的缘故,需要把样式和逻辑分开:所以记录下关键的操作:主要是利用命令代替事件,利用命令传递事件的参数... 先大致看下效果: 主要是利用 Prism 库,可直接利 ...