04-SpringMVC之請求處理流程

SpringMVC之請求處理流程

我們知道DispatcherServlet就是一個HttpServlet,而HttpServlet的請求就從doGet/doPost開始

DispatcherServlet本身沒有實現doGet/doPost,而由他的父類FrameworkServlet實現,源碼如下

FrameworkServlet.doGet/doPost

@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

	processRequest(request, response);
}

/**
* Delegate POST requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

	processRequest(request, response);
}

processRequest

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

    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;
    
    //previousLocaleContext獲取和當前執行緒相關的LocaleContext,根據已有請求構造一個新的和當前執行緒相關的LocaleContext
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = buildLocaleContext(request);

    //previousAttributes獲取和當前執行緒綁定的RequestAttributes
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    
    //為已有請求構造新的ServletRequestAttributes,加入預綁定屬性
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

	//非同步請求處理
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

    //initContextHolders讓新構造的RequestAttributes和ServletRequestAttributes和當前執行緒綁定,加入到ThreadLocal,完成綁定
    initContextHolders(request, localeContext, requestAttributes);

    try {
        //抽象方法doService由FrameworkServlet子類DispatcherServlet重寫
        doService(request, response);
    }catch (ServletException | IOException ex) {
        failureCause = ex;
        throw ex;
    }catch (Throwable ex) {
        failureCause = ex;
        throw new NestedServletException("Request processing failed", ex);
    }finally {
        //解除RequestAttributes,ServletRequestAttributes和當前執行緒的綁定
        resetContextHolders(request, previousLocaleContext, previousAttributes);
        if (requestAttributes != null) {
            requestAttributes.requestCompleted();
        }
        logResult(request, response, failureCause, asyncManager);
        //註冊監聽事件ServletRequestHandledEvent,在調用上下文的時候產生Event
        publishRequestHandledEvent(request, response, startTime, failureCause);
    }
}

doService

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);

    // Keep a snapshot of the request attributes in case of an include,
    // to be able to restore the original attributes after the include.
    Map<String, Object> attributesSnapshot = null;
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap<>();//保存request域中的數據,存一份快照
        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));
            }
        }
    }

    //設置web應用上下文
    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));
        }
        //Flash attributes 在對請求的重定向生效之前被臨時存儲(通常是在session)中,並且在重定向之後被立即移除
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        //FlashMap 被用來管理 flash attributes 而 FlashMapManager 則被用來存儲,獲取和管理 FlashMap 實體
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }

    try {
    	//核心方法
        doDispatch(request, response);
    }finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);//將快照覆蓋回去
            }
        }
    }
}

DispatcherServlet.doDispatch

這個方法就是處理請求的核心方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

	//非同步處理,webflux相關
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            //將request轉換成multipartRequest,並檢查是否解析成功(判斷是否有文件上傳)
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            //根據請求資訊獲取handler(包含了攔截器),組成HandlerExecutionChain
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            //根據handler獲取adapter---命名為ha
            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;
            }

            //執行業務處理,返回視圖模型
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
			//給視圖模型設置viewName
            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);
        }
        //處理請求結果,使用了組件LocaleResolver, ViewResolver和ThemeResolver(view#render)
        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);
            }
        }
    }
}

DispatcherServlet.getHandler

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) {
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

這裡的this.handlerMappings就是9大組件之一,在web容器啟動時方法中初始化.

過濾器和攔截器

  • 過濾器攔截DispatcherServlet,屬於web伺服器層面
  • 攔截器可以攔截到具體方法,屬於springmvc框架

HandlerExecutionChain對象包含處理器+攔截器鏈

public class HandlerExecutionChain {

   private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

	//真正的處理器
   private final Object handler;

	//配置在springmvc配置文件的攔截器
   @Nullable
   private HandlerInterceptor[] interceptors;

	//所有攔截器
   @Nullable
   private List<HandlerInterceptor> interceptorList;

}
AbstractHandlerMapping.getHandler
/**
 * 返回請求處理的HandlerExecutionChain,從AbstractHandlerMapping中的adaptedInterceptors和mappedInterceptors屬性中獲取
 */
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // getHandlerInternal()為抽象方法,具體需子類實現
    Object handler = getHandlerInternal(request);
    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);
    }
    
    // 將請求處理器封裝為HandlerExectionChain
    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;
}

AbstractHandlerMapping.getHandlerExecutionChain
/**
 * 構建handler處理器的HandlerExecutionChain,包括攔截器
 */
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
	//將handler處理成HandlerExecutionChain
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    // 迭代添加攔截器,private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        // 如果攔截器是MappedInterceptor,判斷是否對該handler進行攔截,是的情況下添加
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        } else { 
        	// HandlerInterceptor直接添加,即通過HandingMapping屬性配置的攔截器
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}



// new HandlerExecutionChain(handler),將handler變成HandlerExecutionChain
public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
	if (handler instanceof HandlerExecutionChain) {
		HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
		this.handler = originalChain.getHandler();
		//new一個interceptorList
		this.interceptorList = new ArrayList<>();
		//將HandlerInterceptor合併到interceptorList
		CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
		CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
	}
	else {
		this.handler = handler;
		this.interceptors = interceptors;
	}
}

總結一下

就是把處理器+攔截器鏈組合成HandlerExecutionChain對象,看一下最普通的返回值

image

DispatcherServlet.getHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
   if (this.handlerAdapters != null) {
      for (HandlerAdapter adapter : this.handlerAdapters) {
      	//判斷adapter是否適配handler,適配的話就返回,一般情況下handler是HandlerMethod類型
         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");
         
}


//this.handlerAdapters
private List<HandlerAdapter> handlerAdapters;

//RequestMappingHandlerAdapter的父類AbstractHandlerMethodAdapter的程式碼實現
@Override
public final boolean supports(Object handler) {
	return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

HandlerAdapter就是適配器對象

RequestMappingHandlerAdapter

RequestMappingHandlerAdapter就是處理@RequestMapping註解的適配器

/**
 * Extension of {@link AbstractHandlerMethodAdapter} that supports
 * {@link RequestMapping @RequestMapping} annotated {@link HandlerMethod HandlerMethods}.
 *
 * <p>Support for custom argument and return value types can be added via
 * {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers},
 * or alternatively, to re-configure all argument and return value types,
 * use {@link #setArgumentResolvers} and {@link #setReturnValueHandlers}.
 *
 * @author Rossen Stoyanchev
 * @author Juergen Hoeller
 * @since 3.1
 * @see HandlerMethodArgumentResolver
 * @see HandlerMethodReturnValueHandler
 */
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
      implements BeanFactoryAware, InitializingBean {
      
      ...
      
      
}

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];
         //執行攔截器preHandle方法
         if (!interceptor.preHandle(request, response, this.handler)) {
         	//攔截後的方法afterCompletion
            triggerAfterCompletion(request, response, null);
            return false;
         }
         this.interceptorIndex = i;
      }
   }
   return true;
}

HandlerAdapter.handle

使用適配器執行業務處理,返回視圖模型

@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {

   return handleInternal(request, response, (HandlerMethod) handler);
}
RequestMappingHandlerAdapter.handleInternal
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ModelAndView mav;
   checkRequest(request);

   // 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);
   }

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

   return mav;
}

RequestMappingHandlerAdapter.invokeHandlerMethod

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

   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

      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);
      if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
      }

      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}

invocableMethod.invokeAndHandle

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {
   //這裡就在處理方法,得到返回值
   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
   setResponseStatus(webRequest);

   if (returnValue == null) {
      if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
         disableContentCachingIfNecessary(webRequest);
         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.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
   }
   catch (Exception ex) {
      if (logger.isTraceEnabled()) {
         logger.trace(formatErrorForReturnValue(returnValue), ex);
      }
      throw ex;
   }
}
invokeForRequest();

這個方法就是在處理@RequestMapper註解的方法,並通過反射得到返回值

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {
	//獲取方法參數
   Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
   if (logger.isTraceEnabled()) {
      logger.trace("Arguments: " + Arrays.toString(args));
   }
   //利用反射執行方法,得到返回值
   return doInvoke(args);
}

doInvoke(Object… args)

@Nullable
protected Object doInvoke(Object... args) throws Exception {
   ReflectionUtils.makeAccessible(getBridgedMethod());
   try {
   	  //這裡getBridgedMethod()就是Method,得到Method然後反射執行方法,得到返回值
      return getBridgedMethod().invoke(getBean(), args);
   }
   catch (IllegalArgumentException ex) {
      assertTargetBean(getBridgedMethod(), getBean(), args);
      String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
      throw new IllegalStateException(formatInvokeError(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 {
         throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
      }
   }
}

這裡得到返回值後,springmvc會進行一系列處理,最後用IO write出去

HandlerExecutionChain.applyPostHandle

執行攔截器中postHandle方法

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);
      }
   }
}

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) {
   		//ModelAndViewDefiningException類型,會攜帶對應的ModelAndView
      if (exception instanceof ModelAndViewDefiningException) {
         logger.debug("ModelAndViewDefiningException encountered", exception);
         mv = ((ModelAndViewDefiningException) exception).getModelAndView();
      }
      else {
      	//由對應的處理器handler進行異常處理,返回ModelAndView。其中使用了HandlerExceptionResolver。
         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) {
      //這裡執行攔截器的afterCompletion方法
      // Exception (if any) is already handled..
      mappedHandler.triggerAfterCompletion(request, response, null);
   }
}
mappedHandler.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);
         }
      }
   }
}

HandlerMapping

public interface HandlerMapping {
    // 返回請求的一個處理程式handler和攔截器interceptors
    @Nullable
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

HandlerMapping作用是將請求映射到處理程式,以及預處理和處理後的攔截器列表,映射是基於一些標準的,其中的細節因不同的實現而不相同。這是官方文檔上一段描述,該介面只有一個方法getHandler(request),返回一個HandlerExecutionChain對象

如果配置了這個標籤,Spring MVC會默認添加RequestMappingHandlerMapping和RequestMappingHandlerAdapter

<mvc:annotation-driven />

Spring MVC會載入在當前系統中所有實現了HandlerMapping介面的bean,再進行按優先順序排序。

  • SimpleUrlHandlerMapping 支援映射bean實例和映射bean名稱,需要手工維護urlmap,通過key指定訪問路徑,

  • BeanNameUrlHandlerMapping 支援映射bean的name屬性值,掃描以」/「開頭的beanname,通過id指定訪問路徑

  • RequestMappingHandlerMapping 支援@Controller和@RequestMapping註解,通過註解定義訪問路徑

image

AbstractHandlerMapping

模板類

protected void initApplicationContext() throws BeansException {
    // 提供給子類去重寫的,不過Spring並未去實現,提供擴展
    extendInterceptors(this.interceptors);
    // 載入攔截器
    detectMappedInterceptors(this.adaptedInterceptors);
    // 歸併攔截器
    initInterceptors();
}

/**
 * 空實現
 */
protected void extendInterceptors(List<Object> interceptors) {
}

/**
 * 從上下文中載入MappedInterceptor類型的攔截器,比如我們在配置文件中使用
 * <mvc:interceptors></mvc:interceptors>
 * 標籤配置的攔截器
 */
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
    mappedInterceptors.addAll(
            BeanFactoryUtils.beansOfTypeIncludingAncestors(
                    obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}

/**
 * 合併攔截器,即將<mvc:interceptors></mvc:interceptors>中的攔截器與HandlerMapping中通過屬性interceptors設置的攔截器進行合併
 */
protected void initInterceptors() {
    if (!this.interceptors.isEmpty()) {
        for (int i = 0; i < this.interceptors.size(); i++) {
            Object interceptor = this.interceptors.get(i);
            if (interceptor == null) {
                throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
            }
            // 適配後加入adaptedInterceptors
            this.adaptedInterceptors.add(adaptInterceptor(interceptor));
        }
    }
}

/**
 * 適配HandlerInterceptor和WebRequestInterceptor
 */
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
    if (interceptor instanceof HandlerInterceptor) {
        return (HandlerInterceptor) interceptor;
    } else if (interceptor instanceof WebRequestInterceptor) {
        return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
    } else {
        throw new IllegalArgumentException("Interceptor type not supported: " + 							   													interceptor.getClass().getName());
    }
}

/**
 * 返回請求處理的HandlerExecutionChain,從AbstractHandlerMapping中的adaptedInterceptors和mappedInterceptors屬性中獲取
 */
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // getHandlerInternal()為抽象方法,具體需子類實現
    Object handler = getHandlerInternal(request);
    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);
    }
    
    // 將請求處理器封裝為HandlerExectionChain
    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;
}

/**
 * 鉤子函數,需子類實現
 */
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

/**
 * 構建handler處理器的HandlerExecutionChain,包括攔截器
 */
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    // 迭代添加攔截器
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        // 如果攔截器是MappedInterceptor,判斷是否對該handler進行攔截,是的情況下添加
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        } else { // HandlerInterceptor直接添加,即通過HandingMapping屬性配置的攔截器
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

RequestMappingHandlerMapping

處理註解@RequestMapping及@Controller

  • 實現InitializingBean介面,增加了bean初始化的能力,也就是說在bean初始化時可以做一些控制
  • 實現EmbeddedValueResolverAware介面,即增加了讀取屬性文件的能力

繼承自AbstractHandlerMethodMapping

//RequestMappingHandlerMapping
@Override
public void afterPropertiesSet() {
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setUrlPathHelper(getUrlPathHelper());
    this.config.setPathMatcher(getPathMatcher());
    this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
    this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
    this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
    this.config.setContentNegotiationManager(getContentNegotiationManager());

    super.afterPropertiesSet();
}

//AbstractHandlerMethodMapping
@Override
public void afterPropertiesSet() {
    initHandlerMethods();
}
protected void initHandlerMethods() {
    //獲取上下文中所有bean的name,不包含父容器
    for (String beanName : getCandidateBeanNames()) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            processCandidateBean(beanName);
        }
    }
    //日誌記錄HandlerMethods的總數量
    handlerMethodsInitialized(getHandlerMethods());
}


protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
        //根據name找出bean的類型
        beanType = obtainApplicationContext().getType(beanName);
    } catch (Throwable ex) {
        if (logger.isTraceEnabled()) {
            logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
        }
    }
    //處理Controller和RequestMapping
    if (beanType != null && isHandler(beanType)) {
        detectHandlerMethods(beanName);
    }
}

//RequestMappingHandlerMapping
@Override
protected boolean isHandler(Class<?> beanType) {
    //獲取@Controller和@RequestMapping
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
            AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

//整個controller類的解析過程 
protected void detectHandlerMethods(Object handler) {
    //根據name找出bean的類型
	Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
        //獲取真實的controller,如果是代理類獲取父類
		Class<?> userType = ClassUtils.getUserClass(handlerType);
        //對真實的controller所有的方法進行解析和處理  key為方法對象,T為註解封裝後的對象RequestMappingInfo
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> {
						try {
 // 調用子類RequestMappingHandlerMapping的getMappingForMethod方法進行處理,即根據RequestMapping註解資訊創建匹配條件RequestMappingInfo對象
							return getMappingForMethod(method, userType);
						}catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					});
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		methods.forEach((method, mapping) -> {
                //找出controller中可外部調用的方法
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                //註冊處理方法
				registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}

//requestMapping封裝成RequestMappingInfo對象
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    RequestMappingInfo info = createRequestMappingInfo(method);//解析方法上的requestMapping
    if (info != null) {
        //解析方法所在類上的requestMapping
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
            info = typeInfo.combine(info);//合併類和方法上的路徑,比如Controller類上有@RequestMapping("/demo"),方法的@RequestMapping("/demo1"),結果為"/demo/demo1"
        }
        String prefix = getPathPrefix(handlerType);//合併前綴
        if (prefix != null) {
            info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
        }
    }
    return info;
}

private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
    //找到方法上的RequestMapping註解
    RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, 					   													RequestMapping.class);
    //獲取自定義的類型條件(自定義的RequestMapping註解)
    RequestCondition<?> condition = (element instanceof Class ?
                                     		getCustomTypeCondition((Class<?>) element) : 		 			  											  getCustomMethodCondition((Method) element));
    return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

protected RequestMappingInfo createRequestMappingInfo(
    RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

    //獲取RequestMapping註解的屬性,封裝成RequestMappingInfo對象
    RequestMappingInfo.Builder builder = RequestMappingInfo
        .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
        .methods(requestMapping.method())
        .params(requestMapping.params())
        .headers(requestMapping.headers())
        .consumes(requestMapping.consumes())
        .produces(requestMapping.produces())
        .mappingName(requestMapping.name());
    if (customCondition != null) {
        builder.customCondition(customCondition);
    }
    return builder.options(this.config).build();
}

//再次封裝成對應的對象    面向對象編程  每一個屬性都存在多個值得情況需要排重封裝
@Override
public RequestMappingInfo build() {
    ContentNegotiationManager manager = this.options.getContentNegotiationManager();

    PatternsRequestCondition patternsCondition = new PatternsRequestCondition(
        this.paths, this.options.getUrlPathHelper(), this.options.getPathMatcher(),
        this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(),
        this.options.getFileExtensions());

    return new RequestMappingInfo(this.mappingName, patternsCondition,
                                  new RequestMethodsRequestCondition(this.methods),
                                  new ParamsRequestCondition(this.params),
                                  new HeadersRequestCondition(this.headers),
                                  new ConsumesRequestCondition(this.consumes, this.headers),
                                  new ProducesRequestCondition(this.produces, this.headers, manager),
                                  this.customCondition);
}

registerHandlerMethod

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
   this.mappingRegistry.register(mapping, handler, method);
}
//mapping是RequestMappingInfo對象   handler是controller類的beanName   method為介面方法
public void register(T mapping, Object handler, Method method) {
    ...
    this.readWriteLock.writeLock().lock();
    try {
        //beanName和method封裝成HandlerMethod對象
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        //驗證RequestMappingInfo是否有對應不同的method,有則拋出異常
        validateMethodMapping(handlerMethod, mapping);
        //RequestMappingInfo和handlerMethod綁定
        this.mappingLookup.put(mapping, handlerMethod);

        List<String> directUrls = getDirectUrls(mapping);//可以配置多個url
        for (String url : directUrls) {
            //url和RequestMappingInfo綁定   可以根據url找到RequestMappingInfo,再找到handlerMethod
            this.urlLookup.add(url, mapping);
        }

        String name = null;
        if (getNamingStrategy() != null) {
            name = getNamingStrategy().getName(handlerMethod, mapping);
            addMappingName(name, handlerMethod);//方法名和Method綁定
        }

        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }
		//將RequestMappingInfo  url  handlerMethod綁定到MappingRegistration對象  放入map
        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
        this.readWriteLock.writeLock().unlock();
    }
}

HandlerAdapters

Spring MVC為我們提供了多種處理用戶的處理器(Handler),Spring實現的處理器類型有Servlet、Controller、HttpRequestHandler以及註解類型的處理器,即我們可以通過實現這些介面或者註解我們的類來使用這些處理器,那麼針對不同類型的處理器,如何將用戶請求轉發到相應類型的處理器方法中的呢,這就需求Spring MVC的處理器適配器來完成適配操作,這就是處理器適配器要完成的工作。

  • SimpleServletHandlerAdapter 適配Servlet處理器

  • HttpRerquestHandlerAdapter 適配HttpRequestHandler處理器

  • RequestMappingHandlerAdapter 適配註解處理器

  • SimpleControllerHandlerAdapter 適配Controller處理器

Spring MVC默認使用的處理器適配器為:HttpRequestHandlerAdapter、SimpleServletHandlerAdapter、RequestMappingHandlerAdapter三種。

image

RequestMappingHandlerAdapter

通過繼承抽象類AbstractHandlerMethodAdapter實現了HandlerAdapter介面

請求適配給@RequestMapping類型的Handler處理。

採用反射機制調用url請求對應的Controller中的方法(這其中還包括參數處理),返回執行結果值,完成HandlerAdapter的使命

getLastModified直接返回-1

@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
    return -1;
}

//通過父類調用
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
 
    ModelAndView mav;
    checkRequest(request);
 
    // 判斷當前是否需要支援在同一個session中只能線性地處理請求
    if (this.synchronizeOnSession) {
        // 獲取當前請求的session對象
        HttpSession session = request.getSession(false);
        if (session != null) {
            // 為當前session生成一個唯一的可以用於鎖定的key
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                // 對HandlerMethod進行參數等的適配處理,並調用目標handler
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            // 如果當前不存在session,則直接對HandlerMethod進行適配
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    } else {
        // 如果當前不需要對session進行同步處理,則直接對HandlerMethod進行適配
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }
 
    // 判斷當前請求頭中是否包含Cache-Control請求頭,如果不包含,則對當前response進行處理,為其設置過期時間
    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        // 如果當前SessionAttribute中存在配置的attributes,則為其設置過期時間。
        // 這裡SessionAttribute主要是通過@SessionAttribute註解生成的
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        } else {
            // 如果當前不存在SessionAttributes,則判斷當前是否存在Cache-Control設置,
            // 如果存在,則按照該設置進行response處理,如果不存在,則設置response中的
            // Cache的過期時間為-1,即立即失效
            prepareResponse(response);
        }
    }
    return mav;
}

//核心處理流程
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
 
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // 獲取容器中全局配置的InitBinder和當前HandlerMethod所對應的Controller中配置的InitBinder,用於進行參數的綁定
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        
        // 獲取容器中全局配置的ModelAttribute和當前HandlerMethod所對應的Controller
        // 中配置的ModelAttribute,這些配置的方法將會在目標方法調用之前進行調用
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
 
        // 將handlerMethod封裝為一個ServletInvocableHandlerMethod對象,該對象用於對當前request的整體調用流程進行了封裝
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        
        if (this.argumentResolvers != null) {
            // 設置當前容器中配置的所有ArgumentResolver
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        
        if (this.returnValueHandlers != null) {
            // 設置當前容器中配置的所有ReturnValueHandler
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        
        // 將前面創建的WebDataBinderFactory設置到ServletInvocableHandlerMethod中
        invocableMethod.setDataBinderFactory(binderFactory);
        
        // 設置ParameterNameDiscoverer,該對象將按照一定的規則獲取當前參數的名稱
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
 
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        
        // 這裡initModel()方法主要作用是調用前面獲取到的@ModelAttribute標註的方法,
        // 從而達到@ModelAttribute標註的方法能夠在目標Handler調用之前調用的目的
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
 
        // 獲取當前的AsyncWebRequest,這裡AsyncWebRequest的主要作用是用於判斷目標
        // handler的返回值是否為WebAsyncTask或DefferredResult,如果是這兩種中的一種,
        // 則說明當前請求的處理應該是非同步的。所謂的非同步,指的是當前請求會將Controller中
        // 封裝的業務邏輯放到一個執行緒池中進行調用,待該調用有返回結果之後再返回到response中。
        // 這種處理的優點在於用於請求分發的執行緒能夠解放出來,從而處理更多的請求,只有待目標任務
        // 完成之後才會回來將該非同步任務的結果返回。
        AsyncWebRequest asyncWebRequest = WebAsyncUtils
            .createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);
 
        // 封裝非同步任務的執行緒池,request和interceptors到WebAsyncManager中
        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();
            if (logger.isDebugEnabled()) {
                logger.debug("Found concurrent result value [" + result + "]");
            }
            
            // 封裝非同步任務的處理結果,雖然封裝的是一個HandlerMethod,但只是Spring簡單的封裝
            // 的一個Callable對象,該對象中直接將調用結果返回了。這樣封裝的目的在於能夠統一的
            // 進行右面的ServletInvocableHandlerMethod.invokeAndHandle()方法的調用
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }
 
        // 對請求參數進行處理,調用目標HandlerMethod,並且將返回值封裝為一個ModelAndView對象
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
 
        // 對封裝的ModelAndView進行處理,主要是判斷當前請求是否進行了重定向,如果進行了重定向,
        // 還會判斷是否需要將FlashAttributes封裝到新的請求中
        return getModelAndView(mavContainer, modelFactory, webRequest);
    } finally {
        // 調用request destruction callbacks和對SessionAttributes進行處理
        webRequest.requestCompleted();
    }
}
  • 獲取當前容器中使用@InitBinder註解註冊的屬性轉換器;
  • 獲取當前容器中使用@ModelAttribute標註但沒有使用@RequestMapping標註的方法,並且在調用目標方法之前調用這些方法;
  • 判斷目標handler返回值是否使用了WebAsyncTask或DefferredResult封裝,如果封裝了,則按照非同步任務的方式進行執行;
  • 處理請求參數,調用目標方法和處理返回值。

總結一下

  • 所有請求都會經過DispatcherServlet.doDispatch處理
  • 將請求的內容和攔截器鏈處理成HandlerExecutionChain,一般情況下handler是HandlerMethod類型的,
  • 尋找處理器對應的合適的適配器,一般情況下就是RequestMappingHandlerAdapter,用於處理@RequestMapping註解的適配器
  • 執行攔截器鏈的preHandle方法
  • 使用找到的適配器利用反射去執行方法,獲取返回值,並響應
  • 執行攔截器鏈的postHandle方法
  • 執行攔截器鏈的afterCompletion方法

執行結果如下

/testJson----------------------preHandle
testJson
/testJson----------------------postHandle
/testJson----------------------afterCompletion