Spring MVC DispatcherServlet处理用户请求的流程分析

DispatcherServlet/HandlerMapping/HandlerAdapter/ViewResolver

Posted by Jay on August 14, 2019

Spring MVC DispatcherServlet处理用户请求的流程分析

在前一篇文章Spring MVC启动流程分析(xml配置)中,详细探讨了Spring MVCWeb容器中部署后的启动过程,以及相关源码分析,同时也讨论了DispatcherServlet类的初始化创建过程。本文主要讲解DispatcherServlet类获取用户请求到响应的全过程,并针对相关源码进行分析。

首先,站在Spring MVC的四大组件:DispatcherServletHandlerMappingHandlerAdapter以及ViewResolver的角度来看一下Spring MVC对用户请求的处理过程,有如下流程图:

具体处理过程如下:

  • ① 用户请求发送至DispatcherServlet类进行处理。
  • DispatcherServlet类遍历所有配置的HandlerMapping类,请求查找HandlerHandlerMapping类根据request请求URL等信息查找能够进行处理的Handler,以及相关拦截器HandlerInterceptor并构造HandlerExecutionChain。然后HandlerMapping类将构造的HandlerExecutionChain类的对象返回给前端控制器DispatcherServlet类
  • ③ 前端控制器拿着上一步的Handler遍历所有配置的HandlerAdapter类,请求执行Handler
  • HandlerAdapter类执行相关Handler并获取ModelAndView类的对象,然后将该ModelAndView类的对象返回给前端控制器。
  • DispatcherServlet类遍历所有配置的ViewResolver类,请求进行视图解析。ViewResolver类解析视图后得到View对象并返回给前端控制器。
  • DispatcherServlet类进行视图View的渲染,填充Model
  • DispatcherServlet类向用户返回响应。

通过流程图和上面的讲解不难发现,整个Spring MVC对于用户请求的响应和处理都是以DispatcherServlet类为核心,其他三大组件均与前端控制器进行交互,三大组件之间没有交互并且互相解耦,因此,三大组件可以替换不同的实现而互相没有任何影响,提高了整个架构的稳定性并且降低了耦合度。接下来会按照上述的响应过程逐一进行讲解。

DispatcherServlet类本质上依旧是一个Servlet并且其父类实现了Servlet接口,因为Servlet执行service()方法对用户请求进行响应,根据前一篇文章Spring MVC启动流程分析(xml配置)的分析,可以得到如下的调用逻辑图:

从上图的源码调用逻辑可以看出,HttpServlet抽象类实现了Servlet接口service(ServletRequest, ServletResponse)的方法,因此,用户请求的第一执行方法为该方法,该方法紧接着直接调用了service(HttpServletRequest, HttpServletResponse)方法,其子类FrameworkServlet抽象类重写了该方法,因为多态的特性最终是调用了FrameworkServlet抽象类service(HttpServletRequest, HttpServletResponse)方法,FrameworkServlet抽象类同样也重写了doHead()doPost()doPut()doDelete()doOptions()doTrace()方法,service(ServletRequest, ServletResponse)方法根据请求类型的不同分别调用上述方法,上述六个方法都调用了processRequest()方法,而该方法最终调用了DispatcherServlet类doService()方法。通过层层分析,找到了最终要调用的处理用户请求的方法doService()

下面先看下processRequest()方法的逻辑:

// FrameworkServlet类
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   long startTime = System.currentTimeMillis();
   Throwable failureCause = null;

   LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
   LocaleContext localeContext = buildLocaleContext(request); // 构建LocaleContext

   RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
   // 构建请求属性ServletRequestAttributes
   ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
   asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

   // 将LocaleContext和ServletRequestAttributes绑定到当前线程
   initContextHolders(request, localeContext, requestAttributes);

   try {
      doService(request, response); // DispatcherServlet实现,处理请求
   }
   catch (ServletException | IOException ex) {
      failureCause = ex;
      throw ex;
   }
   catch (Throwable ex) {
      failureCause = ex;
      throw new NestedServletException("Request processing failed", ex);
   }

   finally {
      // 重置线程的LocaleContext和RequestAttributes
      resetContextHolders(request, previousLocaleContext, previousAttributes);
      if (requestAttributes != null) {
         requestAttributes.requestCompleted();
      }
      logResult(request, response, failureCause, asyncManager);
      publishRequestHandledEvent(request, response, startTime, failureCause); // 发布事件
   }
}

processRequest()方法首先构建LocaleContextServletRequestAttributes对象,并将这些对象绑定到当前线程,然后调用 doService(request, response)方法处理用户请求。接下来看DispatcherServlet.doService(request, response)方法的代码:

// DispatcherServlet类
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   logRequest(request); // 日志记录请求

   // 保存属性快照
   Map<String, Object> attributesSnapshot = null;
   if (WebUtils.isIncludeRequest(request)) {
      attributesSnapshot = new HashMap<>();
      Enumeration<?> attrNames = request.getAttributeNames();
      while (attrNames.hasMoreElements()) {
         String attrName = (String) attrNames.nextElement();
         if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
         }
      }
   }

   // 将DispatcherServlet的web应用上下文(子IoC容器)、LocaleResolver等放入请求中,供handler、view对象使用
   request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
   request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
   request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
   request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

   if (this.flashMapManager != null) {
      FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
      if (inputFlashMap != null) {
         request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
      }
      request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
      request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
   }

   try {
      doDispatch(request, response); // 真正进行用户请求的处理
   }
   finally {
      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
         if (attributesSnapshot != null) { // 还原属性
            restoreAttributesAfterInclude(request, attributesSnapshot);
         }
      }
   }
}

doService()方法主要进行一些参数的设置,并将部分参数放入request请求中,真正执行用户请求并作出响应的方法则为doDispatch()方法,查看doDispatch()方法的源码如下:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request; // 用户请求
   HandlerExecutionChain mappedHandler = null; // handler执行链
   boolean multipartRequestParsed = false; // 判断是否解析了文件类型的数据

   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

   try {
      ModelAndView mv = null; // 视图与模型
      Exception dispatchException = null;

      try {
         // 解析MultipartHttpServletRequest请求,检查是否包含文件等类型的数据
         processedRequest = checkMultipart(request); 
         multipartRequestParsed = (processedRequest != request);

         // 根据请求,从HandlerMapping获取HandlerExecutionChain
         mappedHandler = getHandler(processedRequest); 
         if (mappedHandler == null) {
            // 如果HandlerExecutionChain为null,则没有能够进行处理的Handler,返回404
            noHandlerFound(processedRequest, response);
            return;
         }

         // 根据查找到的Handler,获取能够进行处理的HandlerAdapter
         // 获取RequestMappingHandlerAdapter
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); 

         // 判断自上次请求后是否有修改,没有修改直接返回响应
         String method = request.getMethod();
         boolean isGet = "GET".equals(method);
         if (isGet || "HEAD".equals(method)) {
            // -1
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); 
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return; // get请求,且未修改,直接返回
            }
         }

         // 按顺序依次执行HandlerInterceptor的preHandle方法
         // 如果任一HandlerInterceptor的preHandle方法没有通过,则不继续进行处理
         if (!mappedHandler.applyPreHandle(processedRequest, response)) { // 1.应用HandlerInterceptor的preHandle方法
            return; // 返回false,则后续handler的调用不在执行
         }

         // Actually invoke the handler. 2.调用handler(通过HandlerAdapter执行查找到的handler)
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

         applyDefaultViewName(processedRequest, mv); // 应用默认视图名
         // 3.逆序执行HandlerInterceptor的postHandle方法
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
      catch (Exception ex) {
         dispatchException = ex;
      }
      catch (Throwable err) {
         dispatchException = new NestedServletException("Handler dispatch failed", err);
      }
      // 视图渲染,如果有异常,则渲染异常页面
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
      // 如果有异常,按逆序执行所有HandlerInterceptor的afterCompletion方法
      triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
   }
   catch (Throwable err) {
      // 如果有异常,按逆序执行所有HandlerInterceptor的afterCompletion方法
      triggerAfterCompletion(processedRequest, response, mappedHandler,
            new NestedServletException("Handler processing failed", err));
   }
   finally {
      if (asyncManager.isConcurrentHandlingStarted()) {
         if (mappedHandler != null) {
            // 逆序执行所有HandlerInterceptor的afterCompletion方法
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
         }
      }
      else {
         // 如果请求包含文件类型的数据,则进行相关清理工作
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}

根据上述源码并结合文章开始讲解的DispatcherServlet类结合三大组件对用户请求的处理过程,不难理解相关处理流程。

一、查找HandlerExecutionChain

doDispatch()方法通过调用getHandler()方法并传入reuqest,通过HandlerMapping查找HandlerExecutionChain,查看其源码如下:

// DispatcherServlet类
// 根据请求,从HandlerMapping获取HandlerExecutionChain
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) { // 遍历HandlerMapping
         HandlerExecutionChain handler = mapping.getHandler(request); // 根据请求获取处理器执行链
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

getHandler()方法然后调用RequestMappingHandlerMapping.getHandler(HttpServletRequest)方法,具体实现在RequestMappingHandlerMapping的父类AbstractHandlerMapping中:

// AbstractHandlerMapping类
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   Object handler = getHandlerInternal(request); // 根据请求查找HandlerMethod
   if (handler == null) {
      handler = getDefaultHandler();
   }
   if (handler == null) {
      return null;
   }
   // Bean name or resolved handler?
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = obtainApplicationContext().getBean(handlerName);
   }
   // 构建处理器执行链:Handler + HandlerInterceptors
   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

   if (logger.isTraceEnabled()) {
      logger.trace("Mapped to " + handler);
   }
   else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
      logger.debug("Mapped to " + executionChain.getHandler());
   }

   if (CorsUtils.isCorsRequest(request)) {
      CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }

   return executionChain;
}

上面的getHandler(HttpServletRequest)方法中,首先根据请求查找HandlerMethod(Web容器启动时通过扫描Bean,已经缓存了请求信息对应的HandlerMethod),然后根据找到的HandlerMethod和请求HttpServletRequest构建HandlerExecutionChain处理器执行链。

于是,只要RequestMappingHandlerMapping.getHandler(HttpServletRequest)方法找到HandlerExecutionChain执行链,DispatcherServletgetHandler()便会返回。

如果没有找到对应的HandlerExecutionChain对象,则会执行noHandlerFound()方法,继续查看其源码如下:

// 如果HandlerExecutionChain为null,则没有能够进行处理的Handler,返回404
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (pageNotFoundLogger.isWarnEnabled()) {
      pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
   }
   if (this.throwExceptionIfNoHandlerFound) { // false
      throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
            new ServletServerHttpRequest(request).getHeaders());
   }
   else {
      response.sendError(HttpServletResponse.SC_NOT_FOUND); // 返回404
   }
}

如果HandlerExecutionChain为null,则没有能够对请求进行处理的Handler,返回404。

二、查找HandlerAdapter

继续查看doDispatch()方法的源码,如果找到了HandlerExecutionChain,接下来会调用getHandlerAdapter()方法来查找能够对Handler进行处理的HandlerAdapter,查看其源码如下:

// handler: HandlerMethod对象
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { 
   if (this.handlerAdapters != null) {
      for (HandlerAdapter adapter : this.handlerAdapters) {
         if (adapter.supports(handler)) { // RequestMappingHandlerAdapter
            return adapter;
         }
      }
   }
   throw new ServletException("No adapter for handler [" + handler +
         "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

HandlerMapping类似,查找能够处理具体HandlerHandlerAdapter时也会遍历所有配置了的HandlerAdapterHandlerAdapter是一个接口,包含一个support()方法,该方法根据Handler是否实现某个特定的接口来判断该HandlerAdapter是否能够处理这个具体的Handler,这里使用适配器模式,通过这样的方式就可以支持不同类型的HandlerAdapter。如果没有查找到能够处理HandlerHandlerAdapter则会抛出异常。

三、执行HandlerExecutionChain

查找到了对应的HandlerAdapter后(如RequestMappingHandlerAdapter),就会调用HandlerExecutionChainapplyPreHandle()方法来执行配置的所有HandlerInteceptorpreHandle()方法,查看其源码如下:

// 应用HandlerInterceptor的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) { 
   return; // 返回false,则后续handler的调用不在执行
}

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; // preHandle返回false,则剩余的HandlerInterceptor和handler不执行
			}
			this.interceptorIndex = i;
		}
	}
	return true;
}

HandlerExecutionChainapplyPreHandle()方法会按照顺序依次调用HandlerInterceptorpreHandle()方法,但当任一HandlerInterceptorpreHandle()方法返回了false就不再继续执行其他HandlerInterceptorpreHandle()方法,而是直接跳转执行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--) { // 反序执行afterCompletion方法
         HandlerInterceptor interceptor = interceptors[i];
         try {
            interceptor.afterCompletion(request, response, this.handler, ex);
         }
         catch (Throwable ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
         }
      }
   }
}

这里遍历的下标为interceptorIndex,该变量在前一个方法applyPreHandle()方法中赋值,如果preHandle()方法返回true该变量加一,因此该方法会逆序执行所有preHandle()方法返回了trueHandlerInterceptorafterCompletion()方法。

继续阅读doDispatch()方法的源码,如果所有拦截器的preHandle()方法都返回了true,则接下来前端控制器会请求执行上文获取的Handler,并获取到ModelAndView类的对象。

// 调用handler(通过HandlerAdapter执行查找到的handler)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// AbstractHandlerMethodAdapter类
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
	return handleInternal(request, response, (HandlerMethod) handler);
}

// RequestMappingHandlerAdapter类
protected ModelAndView handleInternal(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ModelAndView mav;
	checkRequest(request); // 检查请求方法是否支持、session检查

	// Execute invokeHandlerMethod in synchronized block if required.
	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...
		mav = invokeHandlerMethod(request, response, handlerMethod); // 执行HandlerMethod逻辑
	}

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

	return mav;
}

通过RequestMapppingHandlerAdapter执行Handler时,最终会调用到invokeHandlerMethod()方法,其源码如下:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // ServletRequestDataBinderFactory
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // ModelFactory
      // ServletInvocableHandlerMethod
      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      if (this.argumentResolvers != null) {
         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      if (this.returnValueHandlers != null) {
         invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      }
      invocableMethod.setDataBinderFactory(binderFactory);
      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

      ModelAndViewContainer mavContainer = new ModelAndViewContainer();
      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
      modelFactory.initModel(webRequest, mavContainer, invocableMethod);
      mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
      asyncWebRequest.setTimeout(this.asyncRequestTimeout);

      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      asyncManager.setTaskExecutor(this.taskExecutor);
      asyncManager.setAsyncWebRequest(asyncWebRequest);
      asyncManager.registerCallableInterceptors(this.callableInterceptors);
      asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

      if (asyncManager.hasConcurrentResult()) {
         Object result = asyncManager.getConcurrentResult();
         mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
         asyncManager.clearConcurrentResult();
         LogFormatUtils.traceDebug(logger, traceOn -> {
            String formatted = LogFormatUtils.formatValue(result, !traceOn);
            return "Resume with async result [" + formatted + "]";
         });
         invocableMethod = invocableMethod.wrapConcurrentResult(result);
      }

      invocableMethod.invokeAndHandle(webRequest, mavContainer); // 调用HandlerMethod,并返回响应,设置是否需要视图解析
      if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
      }

      return getModelAndView(mavContainer, modelFactory, webRequest); // 获取ModelAndView
   }
   finally {
      webRequest.requestCompleted();
   }
}

invokeHandlerMethod()方法会将HandlerMethod包装成ServletInvocableHandlerMethod对象,然后调用其invokeAndHandle()方法:

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

   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 调用HandlerMethod
   setResponseStatus(webRequest);

   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);
   Assert.state(this.returnValueHandlers != null, "No return value handlers");
   try {
      // this.returnValueHandlers: HandlerMethodReturnValueHandlerComposite
      this.returnValueHandlers.handleReturnValue( // 处理返回值
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
   }
   catch (Exception ex) {
      if (logger.isTraceEnabled()) {
         logger.trace(formatErrorForReturnValue(returnValue), ex);
      }
      throw ex;
   }
}

invokeAndHandle()方法调用处理器方法HandlerMethod,并处理返回值returnValue(比如将返回值直接写出到Response)。

// this.returnValueHandlers: HandlerMethodReturnValueHandlerComposite
this.returnValueHandlers.handleReturnValue( // 处理返回值
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

处理返回值时的源码如下:

// HandlerMethodReturnValueHandlerComposite类
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
	 // 选择HandlerMethodReturnValueHandler
   HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); 
   if (handler == null) {
      throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
   }
   // handler: RequestResponseBodyMethodProcessor(处理)
   handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}


首先选择HandlerMethodReturnValueHandler对象,这里假设MethodParameter returnType对应的类或方法上带有@ResponseBody注解,则得到的HandlerMethodReturnValueHandlerRequestResponseBodyMethodProcessor对象。接着调用RequestResponseBodyMethodProcessorhandleReturnValue()方法。

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

   mavContainer.setRequestHandled(true);// 不需要再使用ModelAndView进行视图渲染
   ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
   ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

   // Try even with null return value. ResponseBodyAdvice could get involved.
   writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

由于@ResponseBody注解的存在,可以向用户直接返回响应而不需要再使用ModelAndView进行视图渲染处理,因此执行mavContainer.setRequestHandled(true)代码,表示请求已被完全处理完毕、不再需要视图解析。接着调用writeWithMessageConverters()方法,使用HttpMessageConverters将响应内容写出到Response body,返回给请求用户。writeWithMessageConverters()方法中会先进行响应内容的处理,如ResponseBodyAdvice.beforeBodyWrite()以及HttpMessageConverters对内容进行转换,再写出到Response

// 调用handler(通过HandlerAdapter执行查找到的handler)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

在通过HandlerAdapter执行查找到的Handler并获取到ModelAndView类的对象之后,会执行HandlerInterceptorpostHandle()方法:

// 逆序执行HandlerInterceptor的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);

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--) { // 反序执行afterCompletion方法
			HandlerInterceptor interceptor = interceptors[i];
			interceptor.postHandle(request, response, this.handler, mv);
		}
	}
}

可以发现,postHandle()方法是按照逆序执行的。

四、视图渲染

执行完postHandle()方法后,doDispatch()方法调用了processDispatchResult()方法,其源码如下:

// 视图渲染,如果有异常,则渲染异常页面
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

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

	boolean errorView = false;

	// 判断HandlerMapping、HandlerAdapter处理时的异常是否为空
	if (exception != null) {
		// 上述两个组件处理时的异常不为空
		// 如果为ModelAndViewDefiningException异常,则获取一个异常视图
		if (exception instanceof ModelAndViewDefiningException) {
			logger.debug("ModelAndViewDefiningException encountered", exception);
			mv = ((ModelAndViewDefiningException) exception).getModelAndView();
		}
		else {
			// 如果不为ModelAndViewDefiningException异常,进行异常视图的获取
			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
			mv = processHandlerException(request, response, handler, exception);
			errorView = (mv != null);
		}
	}

	// Did the handler return a view to render?
	// 判断mv是否为空,不管是正常的ModelAndView还是异常的ModelAndView,只要存在mv就进行视图渲染
	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) { // 执行HandlerInterceptor的afterCompletion方法
		mappedHandler.triggerAfterCompletion(request, response, null);
	}
}

processDispatchResult()方法传入了一个异常类的对象dispatchException,阅读doDispatch()方法的源码可以看出,Spring MVC对整个doDispatch()方法用了嵌套的try-catch语句,内层的try-catch用于捕获HandlerMapping进行映射查找HandlerExecutionChain以及HandlerAdapter执行具体Handler时的处理异常,并将异常传入到上述processDispatchResult()方法中。

processDispatchResult()方法主要用于视图渲染,该视图可能是正常视图,也可能是针对产生的异常构造的异常视图。然后不管视图是正常视图还是异常视图,均调用render()方法来渲染,查看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 != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
   response.setLocale(locale); // 设置locale

   View view;
   String viewName = mv.getViewName();
   if (viewName != null) {
      // We need to resolve the view name. 使用ViewResolver解析视图
      view = resolveViewName(viewName, mv.getModelInternal(), locale, request); // jsp: InternalResourceView视图
      if (view == null) { //如果视图View为空,抛出异常
         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.
      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.isTraceEnabled()) {
      logger.trace("Rendering view [" + view + "] ");
   }
   try {
      if (mv.getStatus() != null) { // 设置Http响应状态码
         response.setStatus(mv.getStatus().value());
      }
      view.render(mv.getModelInternal(), request, response); // 调用视图View的render方法,通过Model来渲染视图
   }
   catch (Exception ex) {
      if (logger.isDebugEnabled()) {
         logger.debug("Error rendering view [" + view + "]", ex);
      }
      throw ex;
   }
}

render()方法通过调用resolveViewName()方法根据视图名称解析对应的视图View,该方法源码如下:

protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
      Locale locale, HttpServletRequest request) throws Exception {

   if (this.viewResolvers != null) {
      for (ViewResolver viewResolver : this.viewResolvers) {
         // InternalResourceViewResolver
         View view = viewResolver.resolveViewName(viewName, locale); 
         if (view != null) { // InternalResourceView
            return view;
         }
      }
   }
   return null;
}

resolveViewName()方法通过遍历配置的所有ViewResolver类根据视图名称来解析对应的视图View,如果找到则返回对应视图View,没有找到则返回null。默认情况下,得到InternalResourceView对象。

回到前一个render()方法,如果上述方法返回的视图为null则抛出异常,这个异常相信大多数人也见过,当开发时写错了返回的View视图名称时就会抛出该异常。接下来调用具体视图的render()方法来进行Model数据的渲染填充,最终构造成完整的视图。

到这里,doDispatch()的外层try-catch代码块的作用就明显了——为了捕获渲染视图时的异常。通过两层嵌套的try-catchSpring MVC就能够捕获到三大组件HandlerMapping、HandlerAdapter、ViewResolver在处理用户请求时的异常,通过这样的方法能够很方便的实现统一的异常处理。

五、总结

通过前文的源码分析,我们能够清楚的认识到Spring MVC对用户请求的处理过程,进一步加深对Spring MVC的理解。

参考文章