• 所以说这段代码并不难理解,它的核心在于 doDispatch 方法,所以接下来我们就来看看 doDispatch 方法。

    doDispatch

    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.
       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;
        }
       }
       if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
       }
       // Actually invoke the handler.
       mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
       if (asyncManager.isConcurrentHandlingStarted()) {
        return;
       }
       applyDefaultViewName(processedRequest, mv);
       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);
      }
      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));
     }
     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);
       }
      }
     }
    }

    这个方法比较长,涉及到很多组件的处理,这里松哥先和大家把思路梳理畅通,各个组件的详细用法松哥将在以后的文章中和大家仔细分享。

    doDispatch 方法其实主要做了两方面的事情:请求处理以及页面渲染,我们先来看看初始变量的含义:

    接下来再来看看具体的处理逻辑:

    这是 doDispatch 方法的一个大致执行逻辑,doDispatch 里边的 try-catch 有两层,最里边那一层,抛出来的异常会被赋值给 dispatchException 变量,这些异常最终在 processDispatchResult 方法中被处理掉,外面的异常则是 processDispatchResult 方法在执行的过程中抛出的异常,一般来说主要是页面渲染时候的异常。

    processDispatchResult

    最后我们再来看下 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) {
       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 (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);
     }
    }

    可以看到,在 processDispatchResult 方法中首先对异常进行了处理,配置好异常对应的 ModelAndView,然后调用 render 方法对页面进行渲染,最后通过 triggerAfterCompletion 方法去触发拦截器的 afterCompletion 方法。

    小结

    至此,我们就把一个请求的大致流程和大家梳理完了,松哥画了一张流程图我们一起来看下:

    这下相信大家对 doDispatch 方法比较熟悉了,当然这里还涉及到很多组件,这些组件松哥将在后面的文章中和大家逐一进行分析。

    SpringMVC 源码分析之 DispatcherServlet-LMLPHP

    本文分享自微信公众号 - 江南一点雨(a_javaboy)。
    如有侵权,请联系 [email protected] 删除。
    本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

    03-30 09:25