Spring MVC中,拦截器的执行顺序可以通过两种方式进行指定:
- 使用@Order注解,使用@Order注解可以指定拦截器的执行顺序。@Order注解的value值表示拦截器执行的顺序,数值越小的拦截器优先执行。
- 使用order()方法,在addInterceptor()方法中,可以使用order()方法指定拦截器的执行顺序。order()方法的参数是一个整数值,数值越小的拦截器优先执行
- 如果使用了多个拦截器,那么它们的执行顺序将按照添加到拦截器链中的顺序执行。也就是说,先添加的拦截器先执行,后添加的拦截器后执行。如果使用了@Order注解或order()方法来指定拦截器的执行顺序,则会按照指定的顺序执行。
创建拦截器
创建一个实现了 HandlerInterceptor 接口的拦截器类。该接口定义了 3 个方法,分别在请求处理之前、请求处理之后以及完成请求处理后调用。
package com.xy.intercept.intercept; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author 谢阳 * @version 1.8.0_131 * @date 2023/3/16 8:19 * @description */ @Component public class MyIntercept1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // preHandle方法在请求处理前调用,返回true表示继续处理请求,返回false则中断请求处理 System.out.println("preHandle1..."); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // postHandle方法在请求处理后调用,但在视图渲染前,可以在这里对模型和视图进行进一步的处理 System.out.println("postHandle1..."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // afterCompletion方法在视图渲染后调用,可以用于释放资源等操作 System.out.println("afterCompletion1..."); } } package com.xy.intercept.intercept; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author 谢阳 * @version 1.8.0_131 * @date 2023/3/16 8:19 * @description */ @Component public class MyIntercept2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // preHandle方法在请求处理前调用,返回true表示继续处理请求,返回false则中断请求处理 System.out.println("preHandle2..."); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // postHandle方法在请求处理后调用,但在视图渲染前,可以在这里对模型和视图进行进一步的处理 System.out.println("postHandle2..."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // afterCompletion方法在视图渲染后调用,可以用于释放资源等操作 System.out.println("afterCompletion2..."); } }注册拦截器
在Java配置中注册拦截器。如果使用Java配置来配置Spring MVC,可以通过实现WebMvcConfigurer接口中的addInterceptors()方法注册拦截器。
package com.xy.intercept.config; import com.xy.intercept.intercept.MyIntercept1; import com.xy.intercept.intercept.MyIntercept2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @author 谢阳 * @version 1.8.0_131 * @date 2023/3/16 9:29 * @description */ @Configuration @EnableWebMvc public class WebMvcConfig implements WebMvcConfigurer { @Autowired private MyIntercept1 myIntercept1; @Autowired private MyIntercept2 myIntercept2; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myIntercept2).addPathPatterns("/**").order(2); registry.addInterceptor(myIntercept1).addPathPatterns("/**").order(1); } }测试拦截器
测试结果
拦截器核心源码
首先找到DispatcherServlet.java源码
①、②、③分别对应了拦截器的preHandle、postHandle、afterCompletion方法,④对应异常情况下的afterCompletion方法
applyPreHandle源码
/** * Apply preHandle methods of registered interceptors. * @return {@code true} if the execution chain should proceed with the * next interceptor or the handler itself. Else, DispatcherServlet assumes * that this interceptor has already dealt with the response itself. */ 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; }如果为拦截器拦截了,记录当前执行拦截list中多对应的地址,调用triggerAfterCompletion方法如下triggerAfterCompletion源码所示
applyPostHandle源码
/** * Apply postHandle methods of registered interceptors. */ void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { for (int i = this.interceptorList.size() - 1; i >= 0; i--) { HandlerInterceptor interceptor = this.interceptorList.get(i); interceptor.postHandle(request, response, this.handler, mv); } }processDispatchResult源码
/** * Handle the result of handler selection and handler invocation, which is * either a ModelAndView or an Exception to be resolved to a ModelAndView. */ private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned."); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // Exception (if any) is already handled.. mappedHandler.triggerAfterCompletion(request, response, null); } }正常情况下调用倒数第三行代码
triggerAfterCompletion源码
/** * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. * Will just invoke afterCompletion for all interceptors whose preHandle invocation * has successfully completed and returned true. */ void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) { for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = this.interceptorList.get(i); try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } }拦截器的执行顺序分析
-
首先执行applyPreHandle方法,获取拦截器数量,遍历通过 i++ 按传入的拦截器顺序调用 preHandle 拦截过滤,并记录interceptorIndex,如果被过滤则不会执行任何applyPostHandle方法,并记录interceptorIndex调用triggerAfterCompletion方法通过 i-- 调用已执行的拦截器的afterCompletion方法
-
上述正常情况下,执行applyPostHandle,获取拦截器数量,通过遍历 i-- 按传入拦截的逆序调用 postHandle 方法,并记录,并记录interceptorIndex
-
上述正常情况下,执行processDispatchResult,之后会调用mappedHandler.triggerAfterCompletion方法,通过interceptorIndex获取拦截器数量,遍历 i-- 按拦截器执行个数进行逆向执行afterCompletion方法
-
异常情况则直接调用triggerAfterCompletion方法,执行如上