SpringMVC原理(8)-拦截器的执行原理

258 阅读3分钟

我们写一个拦截器之后,那拦截器是在何时执行的呢?多个拦截器之间它们的执行顺序又是怎样的?

让我们带着这些问题来看这篇文章

不知道拦截器怎么获取到的,可以看这篇文章:SpringMVC原理(2)-目标方法是怎么被找到的

HandlerInterceptor

实现一个拦截器,需要实现此接口

 public interface HandlerInterceptor {
 ​
     // 在目标方法执行前调用
     // request对象、response对象、目标方法
     default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
             throws Exception {
 ​
         return true;
     }
 ​
     // 在目标方法执行之后调用,但在视图渲染前调用
     // request对象、response对象、目标方法、目标方法的执行结果
     default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
             @Nullable ModelAndView modelAndView) throws Exception {
     }
 ​
     // 在请求完全处理完毕后调用
     // request对象、response对象、目标方法、异常信息
     default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
             @Nullable Exception ex) throws Exception {
     }
 }

核心方法doDispatch()

 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
     try {
         ModelAndView mv = null;
         Exception dispatchException = null;
 ​
         try {
             
             // 省略代码
             ...
 ​
             // 拦截器前置处理
             if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                 // 前置处理返回false,则终止执行(也就是拦截)
                 return;
             }
 ​
             // 执行目标方法
             mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
 ​
             if (asyncManager.isConcurrentHandlingStarted()) {
                 return;
             }
 ​
             applyDefaultViewName(processedRequest, mv);
             // 拦截器后置处理
             mappedHandler.applyPostHandle(processedRequest, response, mv);
         }
 ​
         // 省略代码
         ...
         // 拦截器最终处理
         processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
     }
     catch (Exception ex) {
         triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
     }
     catch (Throwable err) {
         triggerAfterCompletion(processedRequest, response, mappedHandler,
                                new NestedServletException("Handler processing failed", err));
     }
     
     // 省略代码
     ...
 }

原理

     // ==========================前置处理==================================
     boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
         HandlerInterceptor[] interceptors = getInterceptors();
         if (!ObjectUtils.isEmpty(interceptors)) {
             // 正序遍历所有拦截器,挨个执行 preHandle() 方法
             for (int i = 0; i < interceptors.length; i++) {
                 HandlerInterceptor interceptor = interceptors[i];
                 // 前置处理
                 if (!interceptor.preHandle(request, response, this.handler)) {
                     // 拦截器的最终处理
                     triggerAfterCompletion(request, response, null);
                     // 执行失败,返回false
                     return false;
                 }
                 // 记录执行到哪个拦截器的索引
                 this.interceptorIndex = i;
             }
         }
         return true;
     }
     ​
     ​
     // =========================后置处理====================
     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);
             interceptor.postHandle(request, response, this.handler, mv);
         }
     }
     ​
     // ==========================最终处理==================================
     void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
         // 倒序遍历已经执行过了的拦截器,挨个执行 afterCompletion()
         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);
             }
         }
     }

整个的执行流程

  1. 通过HandlerMapping得到HandlerExecutionChain对象(包括处理器和拦截器链

  2. 拦截器的前置处理:正序遍历所有拦截器,挨个执行preHandle()方法

    1. 如果返回true记录当前执行到哪个拦截器的索引,并执行下一个拦截器的preHandle()

    2. 如果返回false:则执行已经执行过了的拦截器的afterCompletion(),并返回false(代表终止方法

  3. 目标方法的执行

  4. 拦截器的后置处理:倒序遍历所有的拦截器,挨个执行postHandle()

  5. 渲染页面render(mv, request, response)执行完成

  6. 前面所有步骤如果有任何异常,都会执行拦截器的最终处理步骤afterCompletion()

  7. 拦截器的最终处理:拿到执行到哪个拦截器的索引,然后挨个(倒序)执行afterCompletion()

为啥要记录拦截器的索引:执行afterCompletion()会用到

执行流程图

image.png

多个拦截器的执行顺序

image.png