spring mvc 拦截器 (HandlerInterceptor )
Spring MVC 的 拦截器(Interceptor)可以在请求到达 Controller 之前、执行 Controller 之后、视图渲染之前/之后进行拦截和处理。拦截器主要用于日志记录、权限校验、性能监控、通用数据处理等场景。
拦截器的核心接口是HandlerInterceptor ,它定义了三个拦截器行为方法
public interface HandlerInterceptor {// 请求进入 Controller 之前调用,返回 true 才会继续向下执行default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}// Controller 方法调用之后,视图渲染之前调用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 {}
}
执行流程
拦截器链的执行顺序类似于 责任链模式:
- 按配置顺序调用 preHandle()。如果返回 false,后续的拦截器和 Controller 就不会执行。
- 执行目标 Controller方法
- 按配置顺序 逆序调用 postHandle()。
- 最后按配置顺序 逆序调用 afterCompletion()。
注册拦截器
在 Spring Boot 或 Spring MVC 中,需要通过 WebMvcConfigurer 注册拦截器:
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/login", "/error"); // 放行路径}
}
触发时机
拦截器被封装成HandlerExecutionChain 执行链。在DispatchServlet会调用HandlerExecutionChain。
啊doDispatch()方法内通过getHandler()方法获取对应的HandlerExecutionChain
DispatchServlet#doDispatch()相关代码
HandlerExecutionChain mappedHandler = null;
//获取HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;
}// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//调用拦截器preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;
}// 执行目标controller方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;
}applyDefaultViewName(processedRequest, mv);
//执行拦截器PostHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
applyPreHandle方法就是拿出所有的HandlerInterceptor依次调用
HandlerExecutionChain #applyPreHandle()
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i = 0; i < this.interceptorList.size(); i++) {HandlerInterceptor interceptor = this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}return true;}