SpringMVC的拦截器
# 1、拦截器 Interceptor 简介
SpringMVC的拦截器Interceptor规范,主要是对Controller资源访问时进行拦截操作的技术,当然拦截后可以进行权限控制,功能增强等都是可以的。拦截器有点类似 Javaweb 开发中的Filter,拦截器与Filter的区别如下图:

由上图,对Filter 和 Interceptor 做个对比:
| 比较维度 | Filter 技术(过滤器) | Interceptor 技术(拦截器) |
|---|---|---|
| 技术范畴 | JavaWeb 原生技术 | SpringMVC 框架技术 |
| 拦截/过滤资源 | 可对所有请求进行过滤,包括 Servlet、JSP、静态资源等 | 仅拦截进入 SpringMVC 的请求(即 Controller 请求) |
| 执行时机 | 在任何 Servlet 执行之前 | 在 DispatcherServlet 之后执行 |
实现了HandlerInterceptor接口,且被Spring管理的Bean都是拦截器,接口定义如下:
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
HandlerInterceptor接口方法的作用及其参数、返回值详解如下:
| 方法名 | 作用说明 | 参数说明 | 返回值说明 |
|---|---|---|---|
| preHandle | 对拦截到的请求进行预处理,返回 true 表示放行,false 表示终止请求 | Handler:拦截到的 Controller 方法处理器 | boolean:返回 false,请求终止,所有后置方法不执行返回 true,继续执行流程 |
| postHandle | Controller 方法执行后,视图渲染前进行后处理,可修改模型数据与视图 | Handler:拦截到的处理器ModelAndView:返回的模型视图对象 | 无返回值 |
| afterCompletion | 视图渲染完成后执行(整个流程结束后),可用于资源清理、日志记录或异常处理 | Handler:拦截到的处理器Exception:整个流程中出现的异常对象(如果有) | 无返回值 |
# 2、拦截器快速入门
编写MyInterceptor01实现HandlerInterceptor接口:
public class MyInterceptor01 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Controller 方法执行之前...");
return true; // 放行,继续执行后续流程
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Controller 方法执行之后...");
// 可以对 modelAndView 进行修改,比如添加公共数据
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("渲染视图结束,整个流程完毕...");
// 可用于资源清理、日志记录、异常处理等
}
}
配置Interceptor
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--配置对哪些资源进行拦截操作-->
<mvc:mapping path="/*"/>
<bean class="com.itheima.interceptor.MyInterceptor01"></bean>
</mvc:interceptor>
</mvc:interceptors>
# 3、拦截器执行顺序
拦截器三个方法的执行顺序
当每个拦截器都是放行状态时,三个方法的执行顺序如下:

当Interceptor1和Interceptor2处于放行,Interceptor3处于不放行时,三个方法的执行顺序如下:

拦截器执行顺序取决于 interceptor 的配置顺序
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/target"/>
<bean class="com.itheima.interceptor.MyInterceptor02"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/*"/>
<bean class="com.itheima.interceptor.MyInterceptor01"/>
</mvc:interceptor>
</mvc:interceptors>
# 4、拦截器执行原理
请求到来时先会使用组件HandlerMapping去匹配Controller的方法(Handler)和符合拦截路径的Interceptor,Handler和多个Interceptor被封装成一个HandlerExecutionChain的对象HandlerExecutionChain 定义如下:
public class HandlerExecutionChain {
/**
* 映射的 Controller 的处理器对象(可以是 Controller 实例或者具体方法封装)
*/
private final Object handler;
/**
* 当前 Handler 关联的拦截器集合,按顺序执行
*/
private final List<HandlerInterceptor> interceptorList;
// ... 省略其他代码 ...
}
在DispatcherServlet的doDispatch方法中执行拦截器
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
// 根据请求信息获得 HandlerExecutionChain,包含处理器和拦截器链
HandlerExecutionChain mappedHandler = this.getHandler(request);
// 获得对应的处理器适配器(HandlerAdapter),用于调用具体处理器
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
// 执行所有拦截器的前置方法 preHandle
// 如果有一个返回 false,则中断后续流程,直接返回
if (!mappedHandler.applyPreHandle(request, response)) {
return;
}
// 执行处理器(通常是 Controller 中的方法),返回模型和视图信息
ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
// 执行所有拦截器的后置方法 postHandle
mappedHandler.applyPostHandle(request, response, mv);
// 触发所有拦截器的 afterCompletion 方法,处理资源清理和异常等
this.triggerAfterCompletion(request, response, mappedHandler, null /* 异常参数可传 */);
}
跟踪 HandlerExecutionChain的applyPreHandle方法源码:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
// interceptorIndex 用于记录已经执行过的拦截器索引,方便后续调用 afterCompletion
for (int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
// 取出当前拦截器
HandlerInterceptor interceptor = this.interceptorList.get(i);
// 调用当前拦截器的 preHandle 方法
// 如果返回 false,表示拦截请求,后续流程中断
if (!interceptor.preHandle(request, response, this.handler)) {
// 立即触发已经执行过的拦截器的 afterCompletion 方法进行资源清理
this.triggerAfterCompletion(request, response, null);
return false; // 阻止继续执行后续处理器
}
}
return true; // 所有拦截器都放行,继续执行处理器
}
跟踪 HandlerExecutionChain的applyPostHandle方法源码:
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
// 逆序遍历拦截器列表,确保后注册的拦截器先执行 postHandle
for (int i = this.interceptorList.size() - 1; i >= 0; --i) {
// 取出当前拦截器
HandlerInterceptor interceptor = this.interceptorList.get(i);
// 执行拦截器的 postHandle 方法,可对 ModelAndView 进行修改
interceptor.postHandle(request, response, this.handler, mv);
}
}
跟踪HandlerExecutionChain的triggerAfterCompletion方法源码:
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
// 逆向遍历已执行过的拦截器,从最后一个执行过的拦截器开始
for (int i = this.interceptorIndex; i >= 0; --i) {
// 取出当前拦截器
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
// 执行拦截器的 afterCompletion 方法,处理清理或异常处理逻辑
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable t) {
// 记录 afterCompletion 方法中的异常,避免影响后续清理工作
logger.error("HandlerInterceptor.afterCompletion threw exception", t);
}
}
}
