news 2026/4/18 8:18:25

设计模式:责任链模式(springmvc应用)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式:责任链模式(springmvc应用)

目录

一、核心角色对应(责任链模式)

二、场景 1:HandlerInterceptor 拦截器链(核心)

1. 核心流程(请求处理全生命周期)

2. 代码示例(自定义拦截器链)

步骤 1:定义抽象处理者(复用 Spring 原生接口)

步骤 2:实现具体处理者(自定义拦截器)

步骤 3:配置责任链(指定拦截器顺序和拦截路径)

步骤 4:核心处理器(Controller,责任链终点)

3. 执行效果(分场景)

场景 1:请求已登录(token 有效)

场景 2:请求未登录(token 无效)

4. 责任链管理器:HandlerExecutionChain 核心逻辑

三、场景 2:Servlet Filter 过滤器链(底层补充)

1. 代码示例(自定义 Filter)

2. 与 HandlerInterceptor 的核心区别

四、Spring MVC 责任链的核心特点

1. 灵活性

2. 中断性

3. 解耦性

五、典型应用场景

六、总结


Spring MVC 的责任链模式主要体现在两大核心场景:拦截器链(HandlerInterceptor)Servlet 过滤器链(Filter),其中HandlerInterceptor是 Spring MVC 原生封装的责任链,Filter是基于 Servlet 规范的责任链,二者共同构成了请求处理的 “双层责任链”。

核心目标:将请求处理的通用逻辑(如登录校验、日志、跨域)与核心业务逻辑(Controller)解耦,支持按顺序执行、灵活扩展,且可中断请求流程

一、核心角色对应(责任链模式)

责任链模式角色Spring MVC 对应实现核心职责
抽象处理者(Handler)HandlerInterceptor接口 /Filter接口定义处理方法(如preHandle/doFilter),约定处理规则
具体处理者自定义HandlerInterceptor/Filter实现抽象接口,处理特定逻辑(如登录校验、日志记录)
责任链管理器HandlerExecutionChain(拦截器)/FilterChain(过滤器)管理处理者顺序,触发执行,控制请求传递
请求对象HttpServletRequest/HttpServletResponse被传递和处理的核心对象
最终处理者HandlerAdapter+Controller(拦截器链终点)/Servlet(过滤器链终点)责任链传递的最终目标,处理核心业务逻辑

二、场景 1:HandlerInterceptor 拦截器链(核心)

1. 核心流程(请求处理全生命周期)

Spring MVC 拦截器链是不纯责任链(可中断、可部分处理),执行流程如下:

plaintext

DispatcherServlet → 1. 构建 HandlerExecutionChain(包含拦截器列表 + Controller)→ 2. 按序执行拦截器 preHandle(): - 若任意 preHandle 返回 false → 中断链,反向执行已通过拦截器的 afterCompletion(); - 若全部返回 true → 传递到 Controller 执行核心业务 → 3. 倒序执行拦截器 postHandle()(仅 preHandle 全通过)→ 4. 视图渲染完成后,倒序执行拦截器 afterCompletion()(无论是否中断)

2. 代码示例(自定义拦截器链)

步骤 1:定义抽象处理者(复用 Spring 原生接口)

java

运行

// 无需自定义抽象类,直接实现 Spring 提供的 HandlerInterceptor public interface HandlerInterceptor { // 前置处理:请求到达 Controller 前执行,返回 false 中断链 default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } // 后置处理:Controller 执行后、视图渲染前执行(仅 preHandle 全通过) default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {} // 完成后处理:视图渲染后执行(无论是否中断,用于资源清理) default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {} }
步骤 2:实现具体处理者(自定义拦截器)

java

运行

// 1. 登录校验拦截器 @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("token"); if (token == null || !"valid_token".equals(token)) { response.setStatus(401); System.out.println("LoginInterceptor:未登录,中断请求"); return false; // 中断责任链 } System.out.println("LoginInterceptor:登录校验通过"); return true; // 传递给下一个拦截器 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("LoginInterceptor:后置处理(Controller 执行后)"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("LoginInterceptor:完成后处理(资源清理)"); } } // 2. 日志拦截器 @Component public class LogInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("LogInterceptor:记录请求日志 - " + request.getRequestURI()); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("LogInterceptor:记录响应日志 - " + response.getStatus()); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("LogInterceptor:归档日志"); } }
步骤 3:配置责任链(指定拦截器顺序和拦截路径)

java

运行

@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Autowired private LogInterceptor logInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 注册拦截器,指定执行顺序(order 越小,preHandle 越先执行) registry.addInterceptor(logInterceptor) .addPathPatterns("/**") // 拦截所有路径 .order(1); // 日志拦截器先执行 registry.addInterceptor(loginInterceptor) .addPathPatterns("/api/**") // 仅拦截 /api 前缀路径 .order(2); // 登录拦截器后执行 } }
步骤 4:核心处理器(Controller,责任链终点)

java

运行

@RestController @RequestMapping("/api") public class UserController { @GetMapping("/user") public String getUser() { System.out.println("Controller:处理 /api/user 请求"); return "success"; } }

3. 执行效果(分场景)

场景 1:请求已登录(token 有效)

plaintext

LogInterceptor:记录请求日志 - /api/user LoginInterceptor:登录校验通过 Controller:处理 /api/user 请求 LoginInterceptor:后置处理(Controller 执行后) LogInterceptor:记录响应日志 - 200 LoginInterceptor:完成后处理(资源清理) LogInterceptor:归档日志
  • 执行顺序:preHandle(Log → Login)→ Controller → postHandle(Login → Log)→ afterCompletion(Login → Log);
  • 倒序执行原因:HandlerExecutionChain会记录已通过的拦截器索引,反向遍历执行后置 / 完成方法。
场景 2:请求未登录(token 无效)

plaintext

LogInterceptor:记录请求日志 - /api/user LoginInterceptor:未登录,中断请求 LogInterceptor:归档日志
  • 中断逻辑:LoginInterceptor 的 preHandle 返回 false,触发triggerAfterCompletion(),仅执行已通过拦截器(LogInterceptor)的 afterCompletion;
  • 核心 Controller 未执行,postHandle 也不执行。

4. 责任链管理器:HandlerExecutionChain 核心逻辑

Spring MVC 通过HandlerExecutionChain管理拦截器链,核心源码简化如下:

java

运行

public class HandlerExecutionChain { private final Object handler; // 最终的 Controller(Handler) private final List<HandlerInterceptor> interceptors = new ArrayList<>(); private int interceptorIndex = -1; // 记录已通过的拦截器索引 // 执行前置处理 boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { for (int i = 0; i < interceptors.size(); i++) { HandlerInterceptor interceptor = interceptors.get(i); if (!interceptor.preHandle(request, response, handler)) { triggerAfterCompletion(request, response, null); // 中断,执行完成方法 return false; } interceptorIndex = i; // 更新已通过索引 } return true; } // 执行后置处理(倒序) void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { for (int i = interceptors.size() - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors.get(i); interceptor.postHandle(request, response, handler, mv); } } // 执行完成后处理(倒序) void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { for (int i = interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = interceptors.get(i); try { interceptor.afterCompletion(request, response, handler, ex); } catch (Throwable e) { // 忽略异常,保证所有拦截器的完成方法都执行 } } } }

三、场景 2:Servlet Filter 过滤器链(底层补充)

Filter 是 Servlet 规范的责任链,由 Tomcat 等容器管理,执行时机早于 HandlerInterceptor,核心流程:

plaintext

Tomcat → ApplicationFilterChain → Filter1.doFilter() → Filter2.doFilter() → ... → DispatcherServlet.service() → HandlerInterceptor 链 → Controller

1. 代码示例(自定义 Filter)

java

运行

// 字符编码过滤器 @Component public class CharsetFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); System.out.println("CharsetFilter:设置编码为 UTF-8"); chain.doFilter(request, response); // 传递给下一个 Filter } }

2. 与 HandlerInterceptor 的核心区别

维度HandlerInterceptorFilter
所属规范Spring MVC 自定义Servlet 规范
执行时机DispatcherServlet 内部DispatcherServlet 之前
拦截范围仅拦截 Controller 请求拦截所有 Web 请求(如静态资源)
中断方式preHandle 返回 false不调用 chain.doFilter ()
扩展能力可访问 Spring 上下文(注入 Bean)原生 Servlet 接口,无 Spring 依赖

四、Spring MVC 责任链的核心特点

1. 灵活性

  • 动态扩展:新增拦截器只需实现HandlerInterceptor并注册,无需修改原有代码;
  • 顺序可控:通过order()指定执行顺序,适配 “先日志、后校验” 等逻辑;
  • 路径匹配:可指定拦截 / 排除路径,精准控制拦截范围。

2. 中断性

  • 支持 “提前终止请求”(如登录校验失败直接返回 401),避免无效的核心逻辑执行;
  • 中断后仍保证已通过拦截器的afterCompletion执行,避免资源泄漏。

3. 解耦性

  • 请求发送者(客户端)无需知道处理逻辑;
  • 处理者(拦截器)无需知道完整链路,只需关注自身职责;
  • 核心业务(Controller)无需耦合通用逻辑(如日志、校验)。

五、典型应用场景

  1. 权限控制:登录校验、角色 / 数据权限校验;
  2. 日志监控:请求 / 响应日志、接口耗时统计;
  3. 跨域处理:添加 CORS 响应头;
  4. 参数预处理:请求参数解密、XSS 过滤;
  5. 资源清理:线程局部变量(ThreadLocal)清理、连接关闭。

六、总结

Spring MVC 是责任链模式的 “经典落地”:

  1. 核心载体HandlerExecutionChain管理HandlerInterceptor链,是 Spring MVC 原生责任链;
  2. 执行规则:preHandle 正序执行(可中断),postHandle/afterCompletion 倒序执行;
  3. 扩展价值:通过责任链解耦通用逻辑与核心业务,是 Spring MVC 灵活扩展的核心机制;
  4. 双层补充:Filter 链作为底层补充,覆盖更广泛的 Web 请求场景。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 8:16:44

DAY 43

# DAY 43 随机函数与广播机制 知识点回顾: 1. 随机张量的生成: torch.randn函数 2. 卷积和池化的计算公式 (可以不掌握, 会自动计算的) 3. pytorch的广播机制: 加法和乘法的广播机制 ps: numpy运算也有类似的广播机制, 基本一致 作业: 自己多举几个例子帮助自己理解即可…

作者头像 李华
网站建设 2026/4/18 3:46:36

避免数据泄露风险:为什么企业应选择私有化anything-llm?

避免数据泄露风险&#xff1a;为什么企业应选择私有化 Anything-LLM&#xff1f; 在金融、医疗和法律等行业&#xff0c;一份合同、一条患者记录或一封内部邮件的外泄&#xff0c;都可能引发千万级罚款甚至品牌崩塌。而当企业开始尝试用大模型提升效率时&#xff0c;一个现实问…

作者头像 李华
网站建设 2026/4/18 8:06:54

狼群算法求解柔性车间调度问题的Matlab版:有源码提供学习,可直接运行

狼群算法求解柔性车间调度matlab版 有源码提供学习 可直接运行直接打开Matlab&#xff0c;新建个脚本文件咱们就开干。今天要折腾的是用狼群算法解决柔性车间调度这个硬骨头问题。车间里七八台机器&#xff0c;每个工件还有不同的加工路线&#xff0c;这调度方案能把人绕晕&am…

作者头像 李华
网站建设 2026/4/18 7:38:11

使用Vite#x2B; Lit 构建webcomponent 组件

ViteLit.js 构建Web Component web component作为前一个时代的方案&#xff0c;在特定场景下确有不一样的妙用 &#xff0c;在维护前后端不分离的项目&#xff0c;web component 是为数不多的选择&#xff0c;整理一下使用Lit 构建自己的web component组件库为传统项目提提速的…

作者头像 李华
网站建设 2026/4/8 20:56:58

好写作AI:从思绪到结构,一键生成清晰论文大纲

你是否曾面对空白文档&#xff0c;脑中想法万千却不知如何下笔组织&#xff1f;是否花费数小时反复调整论文结构&#xff0c;却总觉逻辑不顺&#xff1f;好写作AI全新功能——一键智能大纲生成&#xff0c;正是为破解这一核心难题而来。它帮你将飘散的思绪&#xff0c;瞬间转化…

作者头像 李华
网站建设 2026/4/18 8:00:22

从缺陷回溯到效能提升:如何构建高价值测试案例知识库

测试案例分析的常见困境与价值重估 在多数软件测试团队中&#xff0c;“测试案例分析”并非一个新名词&#xff0c;但其落地形态却常常流于形式。常见的场景是&#xff1a;在项目复盘会上&#xff0c;某个“经典的”或“严重的”Bug被匆匆回顾&#xff0c;讨论停留在“当时没想…

作者头像 李华