2.Spring MVC源码分析(二)

226 阅读11分钟

1.Spring MVC源码分析(二)

在之前的一篇文章中Spring MVC源码分析(一),已经讲了Spring MVC初始化和执行的大概流程,对于执行的doDispatch方法,我们并没有详细的去说,那么这篇文章就是针对具体的执行去分析。

首先,看下org.springframework.web.servlet.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.
            //1.获取Handler,其实HandlerExecutionChain,这个类包含了Handler和HandlerInterceptor
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
            //2.找到Handler的适配器,因为Handler是Object,所以通过SPI机制,找到对应Handler的适配器
            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 (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            //3.org.springframework.web.servlet.HandlerInterceptor#preHandle
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Actually invoke the handler.
            //4.真正的去执行
            //对于@RequestBody、@ResponseBody、@RestController等注解使用的是AbstractHandlerMethodAdapter
            //这个方法里面主要三步:
                //1.参数解析:涉及转换器
                //2.反射执行
                //3.结果封装:涉及转换器
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            //5.将请求转为视图名称
            applyDefaultViewName(processedRequest, mv);

            //6.org.springframework.web.servlet.HandlerInterceptor#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);
        }
        //7.视图渲染
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        //8.org.springframework.web.servlet.HandlerInterceptor#afterCompletion
        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的执行流程,我们就按照这个注释流程一步一步去看。

1.HandlerMapping和Handler

第一步是根据HandlerMapping获取``Handler,但实际上这里返回的HanlderExecutionChainHandlerExecutionChain里面封装了HanlderHandlerInterceptor,所以说本质上和Handler`是差不多的。

HandlerMapping是一个请求映射器,作用是根据请求来获取能够处理该请求的处理器。

org.springframework.web.servlet.DispatcherServlet#getHandler

/**
* HandlerExecutionChain 是对Handler和HandlerInterceptor的一个封装
* 注意:
* 	1)、Handler是一个Object类型,是为了其他的第三方框架能够实现自己的Handler
* 	2)、HandlerInterceptor其实就是拦截器
* @param request
* @return
* @throws Exception
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //1.HandlerMapping初始化过程已经说过了
    //通过遍历容器中所有的HandlerMapping,获取能够处理该请求的Handler
    for (HandlerMapping hm : this.handlerMappings) {
        if (logger.isTraceEnabled()) {
            logger.trace(
                "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        HandlerExecutionChain handler = hm.getHandler(request);
        if (handler != null) {
            return handler;
        }
    }
    return null;
}

org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler

@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //1.这是获取Handler的核心方法,是一个钩子方法,完全交由子类实现,我们重点是要看这里
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        //2.如果没有找到,获取默认的Handler
        handler = getDefaultHandler();
    }
    if (handler == null) {
        //3.如果都没有找到,doDispatch会判空,抛出404 NotFoundException
        return null;
    }
    // Bean name or resolved handler?
    //4.判断Handler是不是一个Bean
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = getApplicationContext().getBean(handlerName);
    }

    //5.封装HandlerExecutionChain,这里会封装HandlerInterceptor
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    if (CorsUtils.isCorsRequest(request)) {
        //跨域
        CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    return executionChain;
}

下图展示了两个主要实现类:

这里有两个抽象实现,org.springframework.web.servlet.handler.AbstractHandlerMethodMapping是处理所有被@Controller@RequestMapping注解的类;org.springframework.web.servlet.handler.AbstractUrlHandlerMapping根据给定的url进行处理。

这里我们看org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //1.获取请求路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    if (logger.isDebugEnabled()) {
        logger.debug("Looking up handler method for path " + lookupPath);
    }
    this.mappingRegistry.acquireReadLock();
    try {
        //2.根据url 获取Handler
        //HandlerMethod封装了:controller bean、controller bean type、invoke method、invoke method arguments,这也就意味着可以通过反射去执行
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        if (logger.isDebugEnabled()) {
            if (handlerMethod != null) {
                logger.debug("Returning handler method [" + handlerMethod + "]");
            }
            else {
                logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<Match>();
    //1.返回符合的RequestMappingInfo,RequestMappingInfo就是IOC容器启动的时候初始化的扫描所有被@Controller或@RequestMapping注解的类的相关信息
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        //2.设置匹配器
        addMatchingMappings(directPathMatches, matches, request);
    }

    //3.如果没有找到符合的RequestMappingInfo,则设置所有的RequestMappingInfo
    if (matches.isEmpty()) {
        // No choice but to go through all mappings...
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    //4.这一步目地是如果只有一个符合的Handler,直接返回即可,如果有多个符合的Handler,则进行比较,返回一个最合适的
    if (!matches.isEmpty()) {
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
        Collections.sort(matches, comparator);
        if (logger.isTraceEnabled()) {
            logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
                         lookupPath + "] : " + matches);
        }
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
                                                request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
            }
        }
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        handleMatch(bestMatch.mapping, lookupPath, request);
        //5.返回最佳匹配
        return bestMatch.handlerMethod;
    }
    else {
        //6.匹配器不存在返回NULL
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

那么经过这几个步骤之后,我们就已经拿到了HandlerMethod也就是Handler,再经过封装HandlerInterceptor,我们的doDispatch就拿到了一个HandlerExecutionChain类,第一步也就完成了这里我把HandlerExecutionChain这个类贴出来,以便更好的理解这个类。

2.HandlerApapter

根据HandlerExecutionChain类,我们已经知道了Handler是一个Object,目的是为了给其他第三方框架进行扩展。既然Handler是一个Object,那么我么肯定就不可能拿到Handler就直接反射执行,因为直接执行我们会增加很多判断,这对于DispatcherServlet来说是很不友好的,所以Spring MVC就定义了你如果扩展了Handler,那么你也要给一个你的HandlerHandlerAdapterHandlerAdapter是以SPI机制进行加载的。

org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    //1.遍历已经初始化的HandlerAdapter
    for (HandlerAdapter ha : this.handlerAdapters) {
        if (logger.isTraceEnabled()) {
            logger.trace("Testing handler adapter [" + ha + "]");
        }
        //2.判断是否支持这个Handler
        if (ha.supports(handler)) {
            return ha;
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
                               "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}	

org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports

/**
* 专门用来处理HandlerMethod的
* @param handler
* @return
*/
@Override
public final boolean supports(Object handler) {
    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#supportsInternal

/**
 * 总是返回true
 * @param handlerMethod the handler method to check
 * @return
 */
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
    return true;
}

我们第一步拿到的HandlerHandlerMethod,那么在获取HanlderAdapter的时候就比较简单了,拿到的是org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,第二步也就完成了。

3.HandlerAdapter#handle

上一步我们已经拿到了HandlerAdapter,那么下面我们就可以去执行了,因为HandlerInterceptor的存在,在真正的handle之前,需要先执行org.springframework.web.servlet.HandlerInterceptor#preHandle,这里比较简单,我们直接看真正的执行。

org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle

/**
 * This implementation expects the handler to be an {@link HandlerMethod}.
 * 模板方法
 */
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {
	//1.钩子方法,完全交由子类实现
    return handleInternal(request, response, (HandlerMethod) handler);
}

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
                                      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ModelAndView mav;
    //1.检查请求
    checkRequest(request);

    // Execute invokeHandlerMethod in synchronized block if required.
    //2.是否需要加锁
    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // No HttpSession available -> no mutex necessary
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    }
    else {
        // No synchronization on session demanded at all...
        //3.执行,一般会走这里
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            prepareResponse(response);
        }
    }

    return mav;
}

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {

    //1.处理请求
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    setResponseStatus(webRequest);

    //2.非@ResponseBody直接返回
    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    else if (StringUtils.hasText(getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }

    mavContainer.setRequestHandled(false);
    try {
        //3.处理@ResponseBody,涉及转换器
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
        }
        throw ex;
    }
}

org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest

public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
                               Object... providedArgs) throws Exception {

    //1.解析参数
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                     "' with arguments " + Arrays.toString(args));
    }
    //2.反射执行
    Object returnValue = doInvoke(args);
    if (logger.isTraceEnabled()) {
        logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                     "] returned [" + returnValue + "]");
    }
    return returnValue;
}

这个方法有两个重要的步骤:1.解析参数;2.反射执行。

1.解析参数

private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
                                         Object... providedArgs) throws Exception {

    //1.获取方法参数
    MethodParameter[] parameters = getMethodParameters();
    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
        MethodParameter parameter = parameters[i];
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        //2.判断参数类型是否符合
        args[i] = resolveProvidedArgument(parameter, providedArgs);
        if (args[i] != null) {
            continue;
        }
        if (this.argumentResolvers.supportsParameter(parameter)) {
            try {
                //3.解析参数
                args[i] = this.argumentResolvers.resolveArgument(
                    parameter, mavContainer, request, this.dataBinderFactory);
                continue;
            }
            catch (Exception ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
                }
                throw ex;
            }
        }
        if (args[i] == null) {
            throw new IllegalStateException("Could not resolve method parameter at index " +
                                            parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
                                            ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
        }
    }
    //4.返回参数列表
    return args;
}

org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#resolveArgument

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                              NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

    //1.获取参数解析器
    HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    if (resolver == null) {
        throw new IllegalArgumentException("Unsupported parameter type [" +
                                           parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
    }
    //2.@RequestBody 解析参数使用org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
    //我们主要看这里
    return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#resolveArgument

/**
	 * @RequestBody注解参数解析
	 */
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                              NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

    parameter = parameter.nestedIfOptional();
    //1.转换器,我们只要知道这里面是根据Content-Type通过我们配置的转换器来设置参数即可
    Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
    String name = Conventions.getVariableNameForParameter(parameter);

    //2.数据绑定
    WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
    if (arg != null) {
        validateIfApplicable(binder, parameter);
        if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
            throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
        }
    }
    mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());

    //3.是否需要适配参数
    return adaptArgumentIfNecessary(arg, parameter);
}

2.反射执行

protected Object doInvoke(Object... args) throws Exception {
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        //1.反射执行
        return getBridgedMethod().invoke(getBean(), args);
    }
    catch (IllegalArgumentException ex) {
        assertTargetBean(getBridgedMethod(), getBean(), args);
        String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
        throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
    }
    catch (InvocationTargetException ex) {
        // Unwrap for HandlerExceptionResolvers ...
        Throwable targetException = ex.getTargetException();
        if (targetException instanceof RuntimeException) {
            throw (RuntimeException) targetException;
        }
        else if (targetException instanceof Error) {
            throw (Error) targetException;
        }
        else if (targetException instanceof Exception) {
            throw (Exception) targetException;
        }
        else {
            String text = getInvocationErrorMessage("Failed to invoke handler method", args);
            throw new IllegalStateException(text, targetException);
        }
    }
}

到这里我们的Handler也就执行完了,下面就是对返回值进行处理了。这里我们直接看对@ResponseBody的处理。

org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue

@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
                              ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
    if (handler == null) {
        throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    }
    //2.org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#handleReturnValue

@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
                              ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
    throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

    mavContainer.setRequestHandled(true);
    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

    // Try even with null return value. ResponseBodyAdvice could get involved.
    //1.转换器处理
    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

从请求参数处理到返回参数处理,我们都可以看到一个重要的类org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor,这个类就是对@RequestBody@ResponseBody通过转换器进行处理。

到这一步,我们整个Handler就已经执行完成了,这个时候会调用org.springframework.web.servlet.HandlerInterceptor#postHandle进行处理。

4.HandlerExceptionResolver

异常处理器,用于对Handler执行抛出的异常。

org.springframework.web.servlet.DispatcherServlet#processDispatchResult

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

    boolean errorView = false;

    //1.处理异常
    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        }
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            // 2.HandlerExceptionResolver
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // Did the handler return a view to render?
    if (mv != null && !mv.wasCleared()) {
        //3.视图渲染
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        if (logger.isDebugEnabled()) {
            logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                         "': assuming HandlerAdapter completed request handling");
        }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        // Concurrent handling started during a forward
        return;
    }

    if (mappedHandler != null) {
        //4.触发HandlerInterceptor#afterComplete
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

这个方法包含了:1.异常处理;2.视图渲染;3.正常请求的HandlerInterceptor#afterComplete

org.springframework.web.servlet.DispatcherServlet#processHandlerException

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
                                               Object handler, Exception ex) throws Exception {

    // Check registered HandlerExceptionResolvers...
    ModelAndView exMv = null;
    //1.遍历所有的HandlerExceptionResolver,包括我们自定义的,进行异常处理
    for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
        exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
        if (exMv != null) {
            break;
        }
    }
    if (exMv != null) {
        if (exMv.isEmpty()) {
            request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
            return null;
        }
        // We might still need view name translation for a plain error model...
        //2.是否有View
        if (!exMv.hasView()) {
            exMv.setViewName(getDefaultViewName(request));
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
        }
        WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
        return exMv;
    }

    throw ex;
}

至此,异常处理也就完成了,最后下面就是视图渲染了,因为无论是否有异常,有可能包含视图渲染,所以我们可以看到视图渲染render和异常处理processHandlerException是在同一个方法中。

5.ViewResolver

视图解析器,用来查找我们要显示到前端的页面。

org.springframework.web.servlet.DispatcherServlet#render

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Determine locale for request and apply it to the response.
    Locale locale = this.localeResolver.resolveLocale(request);
    response.setLocale(locale);

    View view;
    if (mv.isReference()) {
        //1.根据名称获取视图
        // We need to resolve the view name.
        view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
        if (view == null) {
            throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
                                       "' in servlet with name '" + getServletName() + "'");
        }
    }
    else {
        // No need to lookup: the ModelAndView object contains the actual View object.
        //2.保存的就是视图本身
        view = mv.getView();
        if (view == null) {
            throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                                       "View object in servlet with name '" + getServletName() + "'");
        }
    }

    // Delegate to the View object for rendering.
    if (logger.isDebugEnabled()) {
        logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
    }
    try {
        if (mv.getStatus() != null) {
            response.setStatus(mv.getStatus().value());
        }
        //3.视图渲染
        view.render(mv.getModelInternal(), request, response);
    }
    catch (Exception ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
                         getServletName() + "'", ex);
        }
        throw ex;
    }
}

org.springframework.web.servlet.view.AbstractView#render

@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    if (logger.isTraceEnabled()) {
        logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
                     " and static attributes " + this.staticAttributes);
    }

    //1.创建需要合并的Model,包括static attributes和RequestContext attribute
    Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
    prepareResponse(request, response);
    //2.渲染合并的Model
    renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}

org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel

@Override
protected void renderMergedOutputModel(
    Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

    // Expose the model object as request attributes.
    //1.暴露Model作为Attributes
    exposeModelAsRequestAttributes(model, request);

    // Expose helpers as request attributes, if any.
    //2.如果需要,支持JSTL
    exposeHelpers(request);

    // Determine the path for the request dispatcher.
    //3.确定路径
    String dispatcherPath = prepareForRendering(request, response);

    // Obtain a RequestDispatcher for the target resource (typically a JSP).
    //4.请求分发
    RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
    if (rd == null) {
        throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
                                   "]: Check that the corresponding file exists within your web application archive!");
    }

    // If already included or response already committed, perform include, else forward.
    //5.如果已经执行了,则进行转发,否则执行
    if (useInclude(request, response)) {
        response.setContentType(getContentType());
        if (logger.isDebugEnabled()) {
            logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
        }
        rd.include(request, response);
    }

    else {
        //6.转发
        // Note: The forwarded resource is supposed to determine the content type itself.
        if (logger.isDebugEnabled()) {
            logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
        }
        rd.forward(request, response);
    }
}

正常的流程走完了,上述任何一个步骤发生了异常,都会直接执行HandlerInterceptor#afterComplete方法。