写点什么

Spring 用到的 10 种设计模式,真巧妙!

  • 2025-06-16
    福建
  • 本文字数:4143 字

    阅读完需:约 14 分钟

前言


作为一名有多年开发经验的老司机,每次翻看 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);}
// 实现类:DefaultListableBeanFactorypublic 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@Componentpublic 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 默认作用域


// 源码片段:AbstractBeanFactorypublic 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. 发布事件@Servicepublic class OrderService { @Autowired ApplicationEventPublisher publisher; public void createOrder(Order order) { // 业务逻辑... publisher.publishEvent(new OrderCreatedEvent(order)); }}
// 3. 监听事件@Componentpublic 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


// 伪代码:处理多种Controllerpublic 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中多次读取bodybyte[] 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;    }}
复制代码


实战配置


@Configurationpublic 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 说的:"优雅的代码不是模式的堆砌,而是恰到好处的抽象。"


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


文章转载自:苏三说技术

原文链接:https://www.cnblogs.com/12lisu/p/18930715

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2025-04-01 加入

还未添加个人简介

评论

发布
暂无评论
Spring用到的10种设计模式,真巧妙!_spring_电子尖叫食人鱼_InfoQ写作社区