springmvc源碼解析之DispatcherServlet一

說在前面java

本次主要介紹DispatcherServlet組件,更多精彩請關注」天河聊架構「微信公衆號。ios

 

springmvc配置解析web

進入到這個方法org.springframework.web.servlet.FrameworkServlet#servicespring

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

      HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
      if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
//       執行request請求
         processRequest(request, response);
      }
      else {
         super.service(request, response);
      }
   }

進入到這個方法org.springframework.web.servlet.FrameworkServlet#processRequest跨域

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);
//    獲取請求綁定屬性 -》
      RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
      ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
//    獲取異步請求管理器 -》
      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
//    註冊callable返回值攔截器
      asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//    初始化上下文
      initContextHolders(request, localeContext, requestAttributes);
      try {
//       執行request請求模板方法 -》
         doService(request, response);
      }
      catch (ServletException ex) {
         failureCause = ex;
         throw ex;
      }
      catch (IOException ex) {
         failureCause = ex;
         throw ex;
      }
      catch (Throwable ex) {
         failureCause = ex;
         throw new NestedServletException("Request processing failed", ex);
      }

      finally {
         resetContextHolders(request, previousLocaleContext, previousAttributes);
         if (requestAttributes != null) {
//          -》
            requestAttributes.requestCompleted();
         }

         if (logger.isDebugEnabled()) {
            if (failureCause != null) {
               this.logger.debug("Could not complete request", failureCause);
            }
            else {
               if (asyncManager.isConcurrentHandlingStarted()) {
                  logger.debug("Leaving response open for concurrent processing");
               }
               else {
                  this.logger.debug("Successfully completed request");
               }
            }
         }

//       發佈請求處理事件 -》
         publishRequestHandledEvent(request, response, startTime, failureCause);
      }
   }

進入到這個方法org.springframework.web.context.request.RequestContextHolder#getRequestAttributes微信

public static RequestAttributes getRequestAttributes() {
   RequestAttributes attributes = requestAttributesHolder.get();
   if (attributes == null) {
      attributes = inheritableRequestAttributesHolder.get();
   }
   return attributes;
}

往上返回到這個方法org.springframework.web.context.request.async.WebAsyncUtils#getAsyncManager(javax.servlet.ServletRequest)架構

public static WebAsyncManager getAsyncManager(ServletRequest servletRequest) {
      WebAsyncManager asyncManager = null;
//    從request中獲取請求管理器
      Object asyncManagerAttr = servletRequest.getAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE);
      if (asyncManagerAttr instanceof WebAsyncManager) {
         asyncManager = (WebAsyncManager) asyncManagerAttr;
      }
//    若是沒有就建立後綁定到request中
      if (asyncManager == null) {
         asyncManager = new WebAsyncManager();
         servletRequest.setAttribute(WEB_ASYNC_MANAGER_ATTRIBUTE, asyncManager);
      }
      return asyncManager;
   }

進入到這個方法org.springframework.web.servlet.DispatcherServlet#doServicemvc

@Override
   protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
      if (logger.isDebugEnabled()) {
         String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
         logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
               " processing " + request.getMethod() + " request for [" + getRequestUri(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; //爲include請求保存了一個參數map快照
//    若是是include請求
      if (WebUtils.isIncludeRequest(request)) {
         attributesSnapshot = new HashMap<String, Object>();
//       獲取請求參數
         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));
            }
         }
      }

      // Make framework objects available to handlers and view objects.使框架對象對處理程序和視圖對象可用。
      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());
      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()) {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
               restoreAttributesAfterInclude(request, attributesSnapshot);
            }
         }
      }
   }

進入到這個方法org.springframework.web.servlet.DispatcherServlet#doDispatchapp

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. 獲取請求的handler -》
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
//             找不到handler報錯 -》
               noHandlerFound(processedRequest, response);
               return;
            }

            // Determine handler adapter for the current request.肯定當前請求的處理程序適配器。-》
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
               long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
               if (logger.isDebugEnabled()) {
                  logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
               }
               if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                  return;
               }
            }

//          執行前置攔截器 -》
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
               return;
            }

            // Actually invoke the handler.執行handler -》
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//          若是是異步直接返回
            if (asyncManager.isConcurrentHandlingStarted()) {
               return;
            }

//          解析默認的視圖
            applyDefaultViewName(processedRequest, mv);
//          執行後置攔截器
            mappedHandler.applyPostHandle(processedRequest, response, mv);
         }
         catch (Exception ex) {
            dispatchException = ex;
         }
         catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
         }
         processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
      }
      catch (Exception ex) {
//       異常執行攔截器的完成事件
         triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
      }
      catch (Throwable err) {
         triggerAfterCompletion(processedRequest, response, mappedHandler,
               new NestedServletException("Handler processing failed", err));
      }
      finally {
         if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
               mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
         }
         else {
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
               cleanupMultipart(processedRequest);
            }
         }
      }
   }

進入到這個方法org.springframework.web.servlet.DispatcherServlet#checkMultipartcors

protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
//    判斷是不是上傳文件請求 -》
      if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
         if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
            logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
                  "this typically results from an additional MultipartFilter in web.xml");
         }
         else if (hasMultipartException(request) ) {
            logger.debug("Multipart resolution failed for current request before - " +
                  "skipping re-resolution for undisturbed error rendering");
         }
         else {
            try {
//             解析文件上傳 -》
               return this.multipartResolver.resolveMultipart(request);
            }
            catch (MultipartException ex) {
               if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
                  logger.debug("Multipart resolution failed for error dispatch", ex);
                  // Keep processing error dispatch with regular request handle below
               }
               else {
                  throw ex;
               }
            }
         }
      }
      // If not returned before: return original request.
      return request;
   }

進入到這個方法org.springframework.web.multipart.support.StandardServletMultipartResolver#isMultipart

@Override
   public boolean isMultipart(HttpServletRequest request) {
      // Same check as in Commons FileUpload... 若是不是post請求直接返回
      if (!"post".equalsIgnoreCase(request.getMethod())) {
         return false;
      }
//    請求資源類型中是否包含multipart/
      String contentType = request.getContentType();
      return StringUtils.startsWithIgnoreCase(contentType, "multipart/");
   }

這種是springmvc標準實現,另外一種是common uploiad實現。

往上返回到這個方法org.springframework.web.multipart.support.StandardServletMultipartResolver#resolveMultipart

@Override
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
   return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}

這種是springmvc標準實現。

往上返回到這個方法org.springframework.web.multipart.commons.CommonsMultipartResolver#resolveMultipart

@Override
   public MultipartHttpServletRequest resolveMultipart(final HttpServletRequest request) throws MultipartException {
      Assert.notNull(request, "Request must not be null");
      if (this.resolveLazily) {
         return new DefaultMultipartHttpServletRequest(request) {
            @Override
//          解析上傳文件請求 -》
            protected void initializeMultipart() {
               MultipartParsingResult parsingResult = parseRequest(request);
               setMultipartFiles(parsingResult.getMultipartFiles());
               setMultipartParameters(parsingResult.getMultipartParameters());
               setMultipartParameterContentTypes(parsingResult.getMultipartParameterContentTypes());
            }
         };
      }
      else {
         MultipartParsingResult parsingResult = parseRequest(request);
         return new DefaultMultipartHttpServletRequest(request, parsingResult.getMultipartFiles(),
               parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());
      }
   }

這種是common upload實現。

進入到這個方法org.springframework.web.multipart.commons.CommonsMultipartResolver#parseRequest

protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
//    獲取請求的編碼 -》
      String encoding = determineEncoding(request);
//    準備上傳 -》
      FileUpload fileUpload = prepareFileUpload(encoding);
      try {
//       處理上傳請求
         List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
//       解析上傳文件
         return parseFileItems(fileItems, encoding);
      }
      catch (FileUploadBase.SizeLimitExceededException ex) {
         throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);
      }
      catch (FileUploadBase.FileSizeLimitExceededException ex) {
         throw new MaxUploadSizeExceededException(fileUpload.getFileSizeMax(), ex);
      }
      catch (FileUploadException ex) {
         throw new MultipartException("Failed to parse multipart servlet request", ex);
      }
   }

進入到這個方法org.springframework.web.multipart.commons.CommonsMultipartResolver#determineEncoding

protected String determineEncoding(HttpServletRequest request) {
   String encoding = request.getCharacterEncoding();
   if (encoding == null) {
      encoding = getDefaultEncoding();
   }
   return encoding;
}

往上返回到這個方法org.springframework.web.multipart.commons.CommonsFileUploadSupport#prepareFileUpload

protected FileUpload prepareFileUpload(String encoding) {
      FileUpload fileUpload = getFileUpload();
      FileUpload actualFileUpload = fileUpload;
      // Use new temporary FileUpload instance if the request specifies 若是請求指定,則使用新的臨時FileUpload實例
      // its own encoding that does not match the default encoding.不匹配默認編碼的自身編碼。
      if (encoding != null && !encoding.equals(fileUpload.getHeaderEncoding())) {
         actualFileUpload = newFileUpload(getFileItemFactory());
         actualFileUpload.setSizeMax(fileUpload.getSizeMax());
//       文件上傳文件最大值
         actualFileUpload.setFileSizeMax(fileUpload.getFileSizeMax());
         actualFileUpload.setHeaderEncoding(encoding);
      }

      return actualFileUpload;
   }

往上返回到這個方法org.springframework.web.servlet.DispatcherServlet#getHandler

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
      for (HandlerMapping hm : this.handlerMappings) {
         if (logger.isTraceEnabled()) {
            logger.trace(
                  "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
         }
//       獲取request的handler執行鏈 -》
         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 {
//    根據請求找到hander -》
      Object handler = getHandlerInternal(request);
      if (handler == null) {
//       若是找不到handler就使用默認的handler
         handler = getDefaultHandler();
      }
      if (handler == null) {
         return null;
      }
      // Bean name or resolved handler?
      if (handler instanceof String) {
         String handlerName = (String) handler;
//       從上下文中獲取handler
         handler = getApplicationContext().getBean(handlerName);
      }

//    根據handler和request獲取執行鏈 攔截器和要執行的handler -》
      HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
//    若是是跨域請求,header中有Origin -》
      if (CorsUtils.isCorsRequest(request)) {
//       根據請求獲取跨域配置信息 -》
         CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
//       根據handler和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#getHandlerInternal

@Override
   protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//    根據請求路徑匹配到業務hander方法的路徑
      String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
      if (logger.isDebugEnabled()) {
         logger.debug("Looking up handler method for path " + lookupPath);
      }
      this.mappingRegistry.acquireReadLock();
      try {
//       匹配業務handler方法 -》
         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.util.UrlPathHelper#getLookupPathForRequest

public String getLookupPathForRequest(HttpServletRequest request) {
   // Always use full path within current servlet context? 老是在當前servlet上下文中使用完整路徑? -》
   if (this.alwaysUseFullPath) {
      return getPathWithinApplication(request);
   }
   // Else, use path within current servlet mapping if applicable 不然,在當前servlet映射中使用path(若是適用)
   String rest = getPathWithinServletMapping(request);
   if (!"".equals(rest)) {
      return rest;
   }
   else {
      return getPathWithinApplication(request);
   }
}

進入到這個方法org.springframework.web.util.UrlPathHelper#getPathWithinApplication

public String getPathWithinApplication(HttpServletRequest request) {
//    獲取servlet上下文路徑 -》
      String contextPath = getContextPath(request);
//    獲取資源請求路徑 -》
      String requestUri = getRequestUri(request);
      String path = getRemainingPath(requestUri, contextPath, true);
      if (path != null) {
         // Normal case: URI contains context path.
         return (StringUtils.hasText(path) ? path : "/");
      }
      else {
         return requestUri;
      }
   }

進入到這個方法org.springframework.web.util.UrlPathHelper#getContextPath

public String getContextPath(HttpServletRequest request) {
//    獲取servlet上下文路徑
      String contextPath = (String) request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE);
      if (contextPath == null) {
         contextPath = request.getContextPath();
      }
      if ("/".equals(contextPath)) {
         // Invalid case, but happens for includes on Jetty: silently adapt it.
         contextPath = "";
      }
//    解碼請求 -》
      return decodeRequestString(request, contextPath);
   }

進入到這個方法org.springframework.web.util.UrlPathHelper#decodeRequestString

public String decodeRequestString(HttpServletRequest request, String source) {
      if (this.urlDecode && source != null) {
//       標準解碼 -》
         return decodeInternal(request, source);
      }
      return source;
   }

進入到這個方法org.springframework.web.util.UrlPathHelper#decodeInternal

private String decodeInternal(HttpServletRequest request, String source) {
//    從request中獲取編碼格式,若是沒有采用ISO-8859-1編碼 -》
      String enc = determineEncoding(request);
      try {
         return UriUtils.decode(source, enc);
      }
      catch (UnsupportedEncodingException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Could not decode request string [" + source + "] with encoding '" + enc +
                  "': falling back to platform default encoding; exception message: " + ex.getMessage());
         }
         return URLDecoder.decode(source);
      }
   }

進入到這個方法org.springframework.web.util.UrlPathHelper#determineEncoding

protected String determineEncoding(HttpServletRequest request) {
   String enc = request.getCharacterEncoding();
   if (enc == null) {
      enc = getDefaultEncoding();
   }
   return enc;
}

往上返回到這個方法org.springframework.web.util.UrlPathHelper#getRequestUri

public String getRequestUri(HttpServletRequest request) {
//    從request中獲取請求資源路徑
      String uri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE);
      if (uri == null) {
         uri = request.getRequestURI();
      }
      return decodeAndCleanUriString(request, uri);
   }

往上返回到這個方法org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
      List<Match> matches = new ArrayList<Match>();
//    根據url查找映射
      List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
      if (directPathMatches != null) {
//       添加匹配的映射 -》
         addMatchingMappings(directPathMatches, matches, request);
      }
      if (matches.isEmpty()) {
         // No choice but to go through all mappings...
         addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
      }

      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);
//       hander匹配
         handleMatch(bestMatch.mapping, lookupPath, request);
         return bestMatch.handlerMethod;
      }
      else {
         return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
      }
   }

進入到這個方法org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#addMatchingMappings

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
      for (T mapping : mappings) {
//       獲取匹配的映射 -》
         T match = getMatchingMapping(mapping, request);
         if (match != null) {
            matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
         }
      }
   }

進入到這個方法org.springframework.web.servlet.mvc.method.RequestMappingInfo#getMatchingCondition

@Override
   public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
//    獲取匹配的方法 -》
      RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
//    參數匹配
      ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
//    headers匹配
      HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
      ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
//    -》
      ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
      if (methods == null || params == null || headers == null || consumes == null || produces == null) {
         return null;
      }

      PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
      if (patterns == null) {
         return null;
      }

      RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
      if (custom == null) {
         return null;
      }

      return new RequestMappingInfo(this.name, patterns,
            methods, params, headers, consumes, produces, custom.getCondition());
   }

進入到這個方法org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition#getMatchingCondition

@Override
   public RequestMethodsRequestCondition getMatchingCondition(HttpServletRequest request) {
//    是否跨域 -》
      if (CorsUtils.isPreFlightRequest(request)) {
//       跨域匹配 -》
         return matchPreFlight(request);
      }

      if (getMethods().isEmpty()) {
         if (RequestMethod.OPTIONS.name().equals(request.getMethod()) &&
               !DispatcherType.ERROR.equals(request.getDispatcherType())) {

            return null; // No implicit match for OPTIONS (we handle it)
         }
         return this;
      }

      return matchRequestMethod(request.getMethod());
   }

進入到這個方法org.springframework.web.cors.CorsUtils#isPreFlightRequest

public static boolean isPreFlightRequest(HttpServletRequest request) {
   return (isCorsRequest(request) && HttpMethod.OPTIONS.matches(request.getMethod()) &&
         request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null);
}

往上返回到這個方法org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition#matchPreFlight

private RequestMethodsRequestCondition matchPreFlight(HttpServletRequest request) {
      if (getMethods().isEmpty()) {
         return this;
      }
      String expectedMethod = request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD);
//    匹配請求方法-》
      return matchRequestMethod(expectedMethod);
   }

進入到這個方法org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition#matchRequestMethod

private RequestMethodsRequestCondition matchRequestMethod(String httpMethodValue) {
   HttpMethod httpMethod = HttpMethod.resolve(httpMethodValue);
   if (httpMethod != null) {
      for (RequestMethod method : getMethods()) {
         if (httpMethod.matches(method.name())) {
            return new RequestMethodsRequestCondition(method);
         }
      }
      if (httpMethod == HttpMethod.HEAD && getMethods().contains(RequestMethod.GET)) {
         return GET_CONDITION;
      }
   }
   return null;
}

往上返回到這個方法org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain

 

說到最後

本次源碼解析僅表明我的觀點,僅供參考。

相關文章
相關標籤/搜索