目录
[二、场景 1:HandlerInterceptor 拦截器链(核心)](#二、场景 1:HandlerInterceptor 拦截器链(核心))
[1. 核心流程(请求处理全生命周期)](#1. 核心流程(请求处理全生命周期))
[2. 代码示例(自定义拦截器链)](#2. 代码示例(自定义拦截器链))
[步骤 1:定义抽象处理者(复用 Spring 原生接口)](#步骤 1:定义抽象处理者(复用 Spring 原生接口))
[步骤 2:实现具体处理者(自定义拦截器)](#步骤 2:实现具体处理者(自定义拦截器))
[步骤 3:配置责任链(指定拦截器顺序和拦截路径)](#步骤 3:配置责任链(指定拦截器顺序和拦截路径))
[步骤 4:核心处理器(Controller,责任链终点)](#步骤 4:核心处理器(Controller,责任链终点))
[3. 执行效果(分场景)](#3. 执行效果(分场景))
[场景 1:请求已登录(token 有效)](#场景 1:请求已登录(token 有效))
[场景 2:请求未登录(token 无效)](#场景 2:请求未登录(token 无效))
[4. 责任链管理器:HandlerExecutionChain 核心逻辑](#4. 责任链管理器:HandlerExecutionChain 核心逻辑)
[三、场景 2:Servlet Filter 过滤器链(底层补充)](#三、场景 2:Servlet Filter 过滤器链(底层补充))
[1. 代码示例(自定义 Filter)](#1. 代码示例(自定义 Filter))
[2. 与 HandlerInterceptor 的核心区别](#2. 与 HandlerInterceptor 的核心区别)
[四、Spring MVC 责任链的核心特点](#四、Spring MVC 责任链的核心特点)
[1. 灵活性](#1. 灵活性)
[2. 中断性](#2. 中断性)
[3. 解耦性](#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 的核心区别
| 维度 | HandlerInterceptor | Filter |
|---|---|---|
| 所属规范 | 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)无需耦合通用逻辑(如日志、校验)。
五、典型应用场景
- 权限控制:登录校验、角色 / 数据权限校验;
- 日志监控:请求 / 响应日志、接口耗时统计;
- 跨域处理:添加 CORS 响应头;
- 参数预处理:请求参数解密、XSS 过滤;
- 资源清理:线程局部变量(ThreadLocal)清理、连接关闭。
六、总结
Spring MVC 是责任链模式的 "经典落地":
- 核心载体 :
HandlerExecutionChain管理HandlerInterceptor链,是 Spring MVC 原生责任链; - 执行规则:preHandle 正序执行(可中断),postHandle/afterCompletion 倒序执行;
- 扩展价值:通过责任链解耦通用逻辑与核心业务,是 Spring MVC 灵活扩展的核心机制;
- 双层补充:Filter 链作为底层补充,覆盖更广泛的 Web 请求场景。