找回密码
 立即注册
首页 业界区 业界 Spring用到的10种设计模式,真巧妙!

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

崔和美 2025-9-24 16:50:55
前言

作为一名有多年开发经验的老司机,每次翻看Spring源码都让我感叹:"这哪是框架,分明是设计模式的百科全书!"
有些小伙伴在工作中可能只会用@Autowired,却不知背后藏着多少精妙设计。
今天这篇文章跟大家一起聊聊Spring中最常用的10种设计模式,希望对你会有所帮助。
1 模板方法模式:流程骨架大师

场景:处理重复流程但允许细节变化
Spring应用:JdbcTemplate、RestTemplate等
  1. // 伪代码展示模板方法核心
  2. public abstract class JdbcTemplate {
  3.     // 定义算法骨架(不可重写)
  4.     public final Object execute(String sql) {
  5.         Connection conn = getConnection(); // 抽象方法
  6.         Statement stmt = conn.createStatement();
  7.         ResultSet rs = stmt.executeQuery(sql);
  8.         Object result = mapResult(rs);     // 抽象方法
  9.         releaseResources(conn, stmt, rs);
  10.         return result;
  11.     }
  12.    
  13.     // 留给子类实现的钩子方法
  14.     protected abstract Connection getConnection();
  15.     protected abstract Object mapResult(ResultSet rs);
  16. }
复制代码
为什么用

  • 复用资源管理(连接获取/释放)等通用逻辑
  • 允许子类只关注业务差异(如结果映射)
    思考:当你写重复流程时,想想能否抽出模板骨架
2 工厂模式:对象出生管理局

场景:解耦对象创建与使用
Spring应用:BeanFactory核心接口
  1. public interface BeanFactory {
  2.     Object getBean(String name);
  3.     <T> T getBean(Class<T> requiredType);
  4. }
  5. // 实现类:DefaultListableBeanFactory
  6. public class UserService {
  7.     // 使用者无需关心Bean如何创建
  8.     @Autowired
  9.     private OrderService orderService;
  10. }
复制代码
设计精髓

  • 隐藏复杂的对象初始化过程(如循环依赖处理)
  • 统一管理对象生命周期(单例/原型等作用域)
    类比:就像点外卖不需要知道厨师怎么做菜
3 代理模式:隐形护卫

场景:无侵入增强对象功能
Spring应用:AOP动态代理
  1. // JDK动态代理示例
  2. public class LogProxy implements InvocationHandler {
  3.     private Object target;
  4.    
  5.     public Object createProxy(Object target) {
  6.         this.target = target;
  7.         return Proxy.newProxyInstance(
  8.             target.getClass().getClassLoader(),
  9.             target.getClass().getInterfaces(),
  10.             this);
  11.     }
  12.    
  13.     @Override
  14.     public Object invoke(Object proxy, Method method, Object[] args) {
  15.         System.out.println("【日志】调用方法: " + method.getName());
  16.         return method.invoke(target, args); // 执行原方法
  17.     }
  18. }
  19. // Spring中通过@Aspect实现类似功能
  20. @Aspect
  21. @Component
  22. public class LogAspect {
  23.     @Before("execution(* com.example.service.*.*(..))")
  24.     public void logMethodCall(JoinPoint jp) {
  25.         System.out.println("调用方法: " + jp.getSignature().getName());
  26.     }
  27. }
复制代码
动态代理两板斧

  • JDK代理:基于接口(要求目标类实现接口)
  • CGLIB代理:基于继承(可代理普通类)
    价值:业务逻辑与横切关注点(日志/事务等)彻底解耦
4 单例模式:全局唯一指挥官

场景:减少资源消耗,保证全局一致性
Spring实现:Bean默认作用域
  1. // 源码片段:AbstractBeanFactory
  2. public Object getBean(String name) {
  3.     Object bean = getSingleton(name); // 先查缓存
  4.     if (bean == null) {
  5.         bean = createBean(name);      // 不存在则创建
  6.         addSingleton(name, bean);     // 放入缓存
  7.     }
  8.     return bean;
  9. }
复制代码
关键设计

  • 三级缓存解决循环依赖(singletonObjects, earlySingletonObjects, singletonFactories)
  • 并发安全通过synchronized+双重检查锁定实现
    警示:切忌在单例Bean中保存状态变量!
5 观察者模式:事件广播网

场景:解耦事件生产者和消费者
Spring应用:ApplicationEvent机制
  1. // 1. 定义事件
  2. public class OrderCreatedEvent extends ApplicationEvent {
  3.     public OrderCreatedEvent(Order source) {
  4.         super(source);
  5.     }
  6. }
  7. // 2. 发布事件
  8. @Service
  9. public class OrderService {
  10.     @Autowired ApplicationEventPublisher publisher;
  11.    
  12.     public void createOrder(Order order) {
  13.         // 业务逻辑...
  14.         publisher.publishEvent(new OrderCreatedEvent(order));
  15.     }
  16. }
  17. // 3. 监听事件
  18. @Component
  19. public class EmailListener {
  20.     @EventListener
  21.     public void handleOrderEvent(OrderCreatedEvent event) {
  22.         // 发送邮件通知
  23.     }
  24. }
复制代码
优势

  • 事件源与监听器完全解耦
  • 支持异步处理(加@Async注解即可)
6 策略模式:算法切换器

场景:动态选择算法实现
Spring应用:Resource资源加载
  1. // 资源加载策略族
  2. Resource res1 = new ClassPathResource("config.xml"); // 类路径策略
  3. Resource res2 = new UrlResource("http://config.com");// 网络策略
  4. Resource res3 = new FileSystemResource("/opt/config");// 文件系统策略
  5. // 统一调用接口
  6. InputStream is = res1.getInputStream();
复制代码
源码设计亮点

  • Resource接口统一抽象
  • 通过ResourceLoader自动选择策略
    应用场景:支付方式切换(微信/支付宝/银联)
7 适配器模式:接口转换器

场景:兼容不兼容的接口
Spring应用:Spring MVC的HandlerAdapter
  1. // 伪代码:处理多种Controller
  2. public class RequestMappingHandlerAdapter implements HandlerAdapter {
  3.    
  4.     public boolean supports(Object handler) {
  5.         return handler instanceof Controller;
  6.     }
  7.    
  8.     public ModelAndView handle(HttpRequest req, HttpResponse res, Object handler) {
  9.         Controller controller = (Controller) handler;
  10.         return controller.handleRequest(req, res); // 统一适配调用
  11.     }
  12. }
  13. // 实际Spring源码中处理了:
  14. // 1. @Controller注解类 2. HttpRequestHandler 3. Servlet实现等
复制代码
价值

  • 让DispatcherServlet无需关心Controller具体类型
  • 新增Controller类型只需扩展适配器
8 装饰器模式:功能增强包

场景:动态添加功能
Spring应用:HttpServletRequest包装
  1. // 典型应用:缓存请求体
  2. ContentCachingRequestWrapper wrappedRequest =
  3.     new ContentCachingRequestWrapper(rawRequest);
  4. // 可在filter中多次读取body
  5. byte[] body = wrappedRequest.getContentAsByteArray();
复制代码
源码实现
  1. public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
  2.     private ByteArrayOutputStream cachedContent;
  3.    
  4.     @Override
  5.     public ServletInputStream getInputStream() {
  6.         // 装饰原方法:缓存流数据
  7.     }
  8. }
复制代码
设计本质:通过包装器在不修改原对象基础上增强功能
9 建造者模式:复杂对象组装工

场景:分步构建复杂对象
Spring应用:BeanDefinitionBuilder
  1. // 构建复杂的Bean定义
  2. BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(UserService.class);
  3. builder.addPropertyValue("maxRetry", 3);
  4. builder.setInitMethodName("init");
  5. builder.setScope(BeanDefinition.SCOPE_SINGLETON);
  6. // 注册到容器
  7. registry.registerBeanDefinition("userService", builder.getBeanDefinition());
复制代码
对比传统构造

  • 解决多参数构造的混乱(尤其可选参数多时)
  • 构建过程更加清晰可读
10 责任链模式:拦截器的骨架设计

场景:解耦多步骤处理流程
Spring应用:HandlerInterceptor拦截器链
  1. // Spring MVC核心执行链
  2. public class HandlerExecutionChain {
  3.     private final List<HandlerInterceptor> interceptors = new ArrayList<>();
  4.    
  5.     // 执行前置处理(责任链核心)
  6.     public boolean applyPreHandle(HttpServletRequest request,
  7.                                  HttpServletResponse response) {
  8.         for (int i = 0; i < interceptors.size(); i++) {
  9.             HandlerInterceptor interceptor = interceptors.get(i);
  10.             // 任意拦截器返回false则中断链条
  11.             if (!interceptor.preHandle(request, response, this.handler)) {
  12.                 triggerAfterCompletion(request, response, i); // 清理已完成
  13.                 return false;
  14.             }
  15.         }
  16.         return true;
  17.     }
  18. }
复制代码
实战配置
  1. @Configuration
  2. public class WebConfig implements WebMvcConfigurer {
  3.     @Override
  4.     public void addInterceptors(InterceptorRegistry registry) {
  5.         // 构建责任链
  6.         registry.addInterceptor(new LogInterceptor()).order(1);
  7.         registry.addInterceptor(new AuthInterceptor()).order(2);
  8.         registry.addInterceptor(new RateLimitInterceptor()).order(3);
  9.     }
  10. }
  11. // 独立拦截器实现
  12. public class AuthInterceptor implements HandlerInterceptor {
  13.     @Override
  14.     public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
  15.         if (!checkToken(req.getHeader("Authorization"))) {
  16.             res.sendError(401); // 认证失败
  17.             return false; // 中断链
  18.         }
  19.         return true; // 放行
  20.     }
  21. }
复制代码
设计价值

  • 开闭原则:新增拦截器无需修改现有代码
  • 单一职责:每个拦截器只关注单一功能
  • 动态编排:通过order()灵活调整执行顺序
  • 流程控制:任意节点可中断或继续传递
典型反模式:在拦截器中注入其他拦截器,这将破坏责任链独立性,导致循环依赖!
总结


  • 解耦的艺术
    工厂模式解耦创建/使用,观察者模式解耦事件/处理
  • 扩展性的智慧
    策略模式支持算法扩展,装饰器模式支持功能扩展
  • 复杂性的封装
    模板方法封装流程,建造者模式封装构建
  • 性能的权衡
    单例模式减少资源消耗,代理模式按需增强
最后送给小伙伴们的建议:不要为了用模式而用模式
就像Spring的作者Rod Johnson说的:"优雅的代码不是模式的堆砌,而是恰到好处的抽象。"
当你下次写代码感到别扭时,不妨想想这些经典模式,或许能豁然开朗。
最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下我的同名公众号:苏三说技术,我的所有文章都会在公众号上首发,您的支持是我坚持写作最大的动力。
求一键三连:点赞、转发、在看。
关注公众号:【苏三说技术】,在公众号中回复:进大厂,可以免费获取我最近整理的10万字的面试宝典,好多小伙伴靠这个宝典拿到了多家大厂的offer。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册