36.拦截器的执行时机和原理

1.DispatcherServlet的doDispatch方法

DispatcherServlet的doDispatch方法是请求的入口。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   HandlerExecutionChain mappedHandler = null;
   boolean multipartRequestParsed = false;
 
   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 
   try {
      ModelAndView mv = null;
      Exception dispatchException = null;
 
      try {
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);
 
         // Determine handler for the current request.
         // 拿到请求处理器,里面有拦截器的数组HandlerInterceptor[]
         // 根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }
 
         // Determine handler adapter for the current request.
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
 
         // Process last-modified header, if supported by the handler.
         String method = request.getMethod();
         boolean isGet = "GET".equals(method);
         if (isGet || "HEAD".equals(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return;
            }
         }
         // 目标方法执行之前,会执行该方法
         // 遍历所有拦截器,执行拦截器的preHandle方法
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            // 如果任何一个拦截器返回false。直接跳出不执行目标方法。
            return;
         }
         // 执行目标方法
         // Actually invoke the handler.
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
 
         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }
 
         applyDefaultViewName(processedRequest, mv);
         // 倒叙执行所有拦截器的postHandle方法
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
      catch (Exception ex) {
         dispatchException = ex;
      }
      catch (Throwable err) {
         // As of 4.3, we're processing Errors thrown from handler methods as well,
         // making them available for @ExceptionHandler methods and other scenarios.
         dispatchException = new NestedServletException("Handler dispatch failed", err);
      }
      // 该方法是页面渲染逻辑,页面成功渲染完成以后,也会倒序触发 afterCompletion
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
      // 前面的步骤有任何异常也都会直接倒序触发 afterCompletion
      // 一切正常也会触发afterCompletion
      triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
   }
   catch (Throwable err) {
      // 前面的步骤有任何异常也都会直接倒序触发 afterCompletion
      // 一切正常也会触发afterCompletion
      triggerAfterCompletion(processedRequest, response, mappedHandler,
            new NestedServletException("Handler processing failed", err));
   }
   finally {
      if (asyncManager.isConcurrentHandlingStarted()) {
         // Instead of postHandle and afterCompletion
         if (mappedHandler != null) {
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
         }
      }
      else {
         // Clean up any resources used by a multipart request.
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}

请求处理器,里面有拦截器的数组HandlerInterceptor[]

2.执行拦截器的preHandle方法

先来顺序执行 所有拦截器的 preHandle方法

    ① 如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle方法。

    ② 如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion方法。

如果任何一个拦截器返回false。直接跳出不执行目标方法。

// org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HandlerInterceptor[] interceptors = getInterceptors();
   if (!ObjectUtils.isEmpty(interceptors)) {
      for (int i = 0; i < interceptors.length; i++) {
         HandlerInterceptor interceptor = interceptors[i];
         if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
         }
         this.interceptorIndex = i;
      }
   }
   return true;
}
// org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
      throws Exception {
 
   HandlerInterceptor[] interceptors = getInterceptors();
   if (!ObjectUtils.isEmpty(interceptors)) {
      for (int i = this.interceptorIndex; i >= 0; i--) {
         HandlerInterceptor interceptor = interceptors[i];
         try {
            interceptor.afterCompletion(request, response, this.handler, ex);
         }
         catch (Throwable ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
         }
      }
   }
}

3.倒叙执行所有拦截器的postHandle方法

// org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
      throws Exception {
 
   HandlerInterceptor[] interceptors = getInterceptors();
   if (!ObjectUtils.isEmpty(interceptors)) {
      for (int i = interceptors.length - 1; i >= 0; i--) {
         HandlerInterceptor interceptor = interceptors[i];
         interceptor.postHandle(request, response, this.handler, mv);
      }
   }
}

4.页面成功渲染完成以后触发 afterCompletion

// org.springframework.web.servlet.DispatcherServlet#processDispatchResult
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..
      // 页面成功渲染完成以后触发 afterCompletion
      mappedHandler.triggerAfterCompletion(request, response, null);
   }
}

页面成功渲染完成以后,也会倒序触发 afterCompletion

// org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
      throws Exception {
 
   HandlerInterceptor[] interceptors = getInterceptors();
   if (!ObjectUtils.isEmpty(interceptors)) {
      for (int i = this.interceptorIndex; i >= 0; i--) {
         HandlerInterceptor interceptor = interceptors[i];
         try {
            interceptor.afterCompletion(request, response, this.handler, ex);
         }
         catch (Throwable ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
         }
      }
   }
}

6.总结

1、根据当前请求,找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】

2、先来顺序执行 所有拦截器的 preHandle方法

(1)、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle

(2)、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;

3、如果任何一个拦截器返回false。直接跳出不执行目标方法

4、所有拦截器都返回True。则继续执行目标方法

5、目标方法执行完成之后,倒序执行所有拦截器的postHandle方法。

6、前面的步骤有任何异常都会直接倒序触发 afterCompletion

7、页面成功渲染完成以后,也会倒序触发 afterCompletion

posted @ 2022-08-08 13:59  随遇而安==  阅读(102)  评论(0编辑  收藏  举报