欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談SpringMVC請求映射handler源碼解讀

 更新時間:2021年03月18日 09:18:23   作者:是馮吉榮呀  
這篇文章主要介紹了淺談SpringMVC請求映射handler源碼解讀,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

請求映射源碼

首先看一張請求完整流轉(zhuǎn)圖(這里感謝博客園上這位大神的圖,博客地址我忘記了):

前臺發(fā)送給后臺的訪問請求是如何找到對應(yīng)的控制器映射并執(zhí)行后續(xù)的后臺操作呢,其核心為DispatcherServlet.java與HandlerMapper。在spring boot初始化的時候,將會加載所有的請求與對應(yīng)的處理器映射為HandlerMapper組件。我們可以在springMVC的自動配置類中找到對應(yīng)的Bean。

@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(
  @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
  @Qualifier("mvcConversionService") FormattingConversionService conversionService,
  @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
  // Must be @Primary for MvcUriComponentsBuilder to work
  return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
                       resourceUrlProvider);
}

@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
                              FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
  WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
    new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
    this.mvcProperties.getStaticPathPattern());
  welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
  welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
  return welcomePageHandlerMapping;
}

請求將首先執(zhí)行FrameworkServlet下的service方法根據(jù)request請求的method找到對應(yīng)的do**方法。

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

  HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
  if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
    processRequest(request, response);
  }
  else {
    //父類根據(jù)method參數(shù)執(zhí)行doGet,doPost,doDelete等
    super.service(request, response);
  }
}

而這些do**其都會進入核心方法,以doGet為例。

@Overrideprotected 
final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  //核心方法
  processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
  try {
  //進入此核心方法
  doService(request, response);
}
catch (ServletException | 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();
  }
  logResult(request, response, failureCause, asyncManager);
  publishRequestHandledEvent(request, response, startTime, failureCause);
}

processRequest()方法中重點在doService(request, response);,而其核心處理邏輯位于DispatchServletl類重寫的方法,如下。

@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
 ····

   try {
     //這里為實際分發(fā)控制器的邏輯,其內(nèi)部是找到對應(yīng)的handlerMapper
     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);
        }
      }
      if (requestPath != null) {
        ServletRequestPathUtils.clearParsedRequestPath(request);
      }
    }
}

接下來看分發(fā)處理邏輯方法,其中重要的方法都使用了原生的注釋。接下來分別分析核心源碼。

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

  WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

    try {
      processedRequest = checkMultipart(request);
      multipartRequestParsed = (processedRequest != request);

      // Determine handler for the current request.
      mappedHandler = getHandler(processedRequest);
      if (mappedHandler == null) {
        noHandlerFound(processedRequest, response);
        return;
      }

      // Determine handler adapter for the current request.
      HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

      // Process last-modified header, if supported by the handler.
      String method = request.getMethod();
      boolean isGet = "GET".equals(method);
      if (isGet || "HEAD".equals(method)) {
        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
        if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
          return;
        }
      }

      if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
      }

      // Actually invoke the handler.
      mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

      applyDefaultViewName(processedRequest, mv);
      mappedHandler.applyPostHandle(processedRequest, response, mv);
    }
    catch (Exception ex) {
      dispatchException = ex;
    }
    catch (Throwable err) {
      // As of 4.3, we're processing Errors thrown from handler methods as well,
      // making them available for @ExceptionHandler methods and other scenarios.
      dispatchException = new NestedServletException("Handler dispatch failed", err);
    }
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  }
  catch (Exception ex) {
    triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  }
  catch (Throwable err) {
    triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
  }
  finally {
    if (asyncManager.isConcurrentHandlingStarted()) {
      // Instead of postHandle and afterCompletion
      if (mappedHandler != null) {
        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
      }
    }
    else {
      // Clean up any resources used by a multipart request.
      if (multipartRequestParsed) {
        cleanupMultipart(processedRequest);
      }
    }
  }
}

首先是分析getHandler(),找到對應(yīng)的處理器映射邏輯。

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

我們將斷點標記在getHandler方法上時,可以清除看到handlerMappings,如圖。

這里,用戶請求與處理器的映射關(guān)系都在RequestMapperHandlerMapping中,而歡迎頁處理請求則在WelcomePageHanderMapping中進行映射。

以下為RequestMapperHandlerMapping中映射部分截圖,可以看到用戶的所有請求映射這里面都有:

getHandler()后的方法是通過比較request請求中method與HandlerMapper中相同url下的method,再進行唯一性校驗,不通過異常,通過找到唯一的handler。

后續(xù),通過handler找到處理的設(shè)配器,通過適配器得到一個ModelAndView對象,這個對象就是最后返回給前端頁面的對象。

至此,一個請求完整映射到返回前端結(jié)束。

說明:這是實現(xiàn)了FramworkServlet的doService方法,F(xiàn)ramworkServlet繼承自HttpServlet,并且重寫了父類中的doGet(),doPost(),doPut(),doDelete 等方法,在這些重寫的方法里都調(diào)用了 processRquest() 方法做請求處理,進入processRquest()可以看到里面調(diào)用了FramworkServlet中定義的doService() 方法。

到此這篇關(guān)于淺談SpringMVC請求映射handler源碼解讀的文章就介紹到這了,更多相關(guān)SpringMVC請求映射handler 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中HTTP GET方法調(diào)用帶有body的問題解決

    Java中HTTP GET方法調(diào)用帶有body的問題解決

    這篇文章主要為大家詳細介紹了Java如何解決HTTP GET方法調(diào)用帶有body的問題,文中的示例代碼講解詳細,感興趣的小伙伴可以參考一下
    2024-02-02
  • 關(guān)于Springboot打成JAR包后讀取外部配置文件的問題

    關(guān)于Springboot打成JAR包后讀取外部配置文件的問題

    這篇文章主要介紹了關(guān)于Springboot打成JAR包后讀取外部配置文件的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Springboot AOP對指定敏感字段數(shù)據(jù)加密存儲的實現(xiàn)

    Springboot AOP對指定敏感字段數(shù)據(jù)加密存儲的實現(xiàn)

    本篇文章主要介紹了利用Springboot+AOP對指定的敏感數(shù)據(jù)進行加密存儲以及對數(shù)據(jù)中加密的數(shù)據(jù)的解密的方法,代碼詳細,具有一定的價值,感興趣的小伙伴可以了解一下
    2021-11-11
  • Spring Boot集成SpringFox 3.0與Pageable參數(shù)處理方法

    Spring Boot集成SpringFox 3.0與Pageable參數(shù)處理方法

    這篇文章主要介紹了Spring Boot集成SpringFox 3.0與Pageable參數(shù)處理,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-10-10
  • JAVA中@ApiModel和@ApiModelProperty注解實戰(zhàn)代碼

    JAVA中@ApiModel和@ApiModelProperty注解實戰(zhàn)代碼

    這篇文章主要給大家介紹了關(guān)于JAVA中@ApiModel和@ApiModelProperty注解的相關(guān)資料,@ApiModel注解是用在接口相關(guān)的實體類上的注解,它主要是用來對使用該注解的接口相關(guān)的實體類添加額外的描述信息,常常和@ApiModelProperty注解配合使用,需要的朋友可以參考下
    2024-03-03
  • Java多線程中的Future類詳細解讀

    Java多線程中的Future類詳細解讀

    這篇文章主要介紹了Java多線程中的Future類詳細解讀,Future表示一個可能還沒有完成的異步任務(wù)的結(jié)果,針對這個結(jié)果可以添加Callback以便在任務(wù)執(zhí)行成功或失敗后作出相應(yīng)的操作,需要的朋友可以參考下
    2023-11-11
  • Java增強for循環(huán)的增刪操作代碼

    Java增強for循環(huán)的增刪操作代碼

    Foreach循環(huán)(Foreach loop)是計算機編程語言中的一種控制流程語句,通常用來循環(huán)遍歷數(shù)組或集合中的元素,本文通過實例演示普通for循環(huán)和foreach循環(huán)使用,java增強for循環(huán)的操作代碼感興趣的朋友一起看看吧
    2024-02-02
  • java轉(zhuǎn)發(fā)和重定向的區(qū)別

    java轉(zhuǎn)發(fā)和重定向的區(qū)別

    這篇文章主要介紹了java轉(zhuǎn)發(fā)和重定向的區(qū)別,需要的朋友可以參考下
    2014-10-10
  • Spring boot實現(xiàn)應(yīng)用打包部署的示例

    Spring boot實現(xiàn)應(yīng)用打包部署的示例

    本篇文章主要介紹了Spring boot實現(xiàn)應(yīng)用打包部署的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • 淺談SpringMVC對RESTfull的支持

    淺談SpringMVC對RESTfull的支持

    這篇文章主要介紹了淺談SpringMVC對RESTfull的支持,分享了相關(guān)配置代碼,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02

最新評論