Spring MVC中的HandlerMapping與HandlerAdapter,springmvcmapping

來源:互聯網
上載者:User

Spring MVC中的HandlerMapping與HandlerAdapter,springmvcmapping
Spring MVC中的HandlerMapping與HandlerAdapter的關係

最近和同事討論一個spring mvc的問題,問到HandlerMapping與HandlerAdapter有什麼關係?雖然使用spring mvc時間也不短,但是瞬間能起來的只有兩個關鍵詞:

  • @RequestMapping,這個經常用的,每個 Controller下面的action方法上一般都會定義一個特有的url路徑。當HTTP請求請求發送到服務端後會根據url來尋找應該執行哪個Controller下面的哪個action,我理解為url與java代碼的一個路由關係。
    @RequestMapping(value = "/bss/{priceId}", method = RequestMethod.GET)    public ValueResult<ProductPrice> getProductPrice(HttpServletRequest request,                                                                 @Min(value = 1,message = "priceId不合法")                                                                 @PathVariable final long priceId)  {        //省略    }
  • HandlerInterceptor,這個也是經常用的,做請求攔截時比較常用。

上面兩個關鍵詞儘管與問題有所關聯,但很明顯不是主要的,核心還是這兩個介面都是做什麼的,兩者之間有什麼互動。於是我們可以從一個請求開始調試下spring mvc的調用過程,以此來分析它們的作用以及關係。

Spring MVC配置兩個設定檔:
  • 應用程式層級的applicationContext.xml,一般載入非web的配置,比如資料庫配置,redis配置等等。
  • web層級的mvc-dispatcher-servlet.xml,這裡專註mvc的配置。
XmlWebApplicationContext context = new XmlWebApplicationContext();context.setConfigLocations(new String[]{"classpath*:applicationContext.xml","classpath*:spring/mvc-dispatcher-servlet.xml"});ServletContextHandler spingMvcHandler = new ServletContextHandler();spingMvcHandler.setContextPath(appConfig.getContext());spingMvcHandler.addEventListener(new ContextLoaderListener(context));spingMvcHandler.addServlet(new ServletHolder(new DispatcherServlet(context)), "/*");

 這裡引用《張開濤》同學的圖來說明上面兩個配置的作用以及關係:

  兩個核心類
  • ContextLoaderListener
    這的作用主要是在啟動web容器時載入ApplicationContext的資訊,用來建立ROOT ApplicationContext的,可以接收XML類型的,比如XmlWebApplicationContext,它將從XML設定檔中載入配置資訊。

這篇它不是重點至此主止。

  • DispatcherServlet
    也叫前端控制器,它是Spring MVC的統一訪問入口,負責職責的分配以及工作調試,由於它的功能複雜這裡只關心與HandlerMapping與HandlerAdaper的內容。下面是初始化的功能,其中有初始化HandlerMapping與HandlerAdaper。
@Overrideprotected void onRefresh(ApplicationContext context) {initStrategies(context);}/** * Initialize the strategy objects that this servlet uses. * <p>May be overridden in subclasses in order to initialize further strategy objects. */protected void initStrategies(ApplicationContext context) {//其它初始化initHandlerMappings(context);initHandlerAdapters(context);//其它初始化}

initHandlerMappings,主要是調用BeanFactoryUtils.beansOfTypeIncludingAncestors,其中一種非常重要的HandlerMapping是RequestMappingHandlerMapping,我們通過在Controller方面上加@RequestMapping注釋來配合使用,系統會將我們配置的RequestMapping資訊註冊到其中,詳細資料參數此圖:mappingRegistry中包含了所有的請求路由資訊。

代碼如下:

private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;if (this.detectAllHandlerMappings) {// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());// We keep HandlerMappings in sorted order.AnnotationAwareOrderComparator.sort(this.handlerMappings);}}//不載入全部的先省略//載入預設的邏輯先省略}

DispatcherServlet核心方法:doDispatch,三個重要步驟:

  • getHandler,擷取頁面處理器,通俗點就是擷取由哪個Controller來執行,包含方法資訊以及方法參數等資訊。
  • getHandlerAdapter,擷取HandlerAdapter,它包含一個handle方法,負責調用真實的頁面處理器進行請求處理並返回一個ModelAndView。HandlerAdpter裡面有一些常見的處理,比如訊息轉移,參數處理等,詳見此圖:裡面的argumentResolvers可以用來處理請求的參數,messageConverts是作訊息轉換等等。

    

  • HandlerAdapter.handle,執行真實頁面處理器的處理請求。
請求時序圖(只關注HandlerMapping與HandlerAdapter)

doDispath擷取頁面處理器,然後根據頁面處理器擷取對應的HanlerAdapter,最後由HanlerAdaper來調用頁面處理器的方法。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {//初始化省略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 || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//其它邏輯省略// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//其它邏輯省略}catch (Exception ex) {dispatchException = ex;}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}//異常邏輯省略}

具體的調用邏輯比較複雜,只選取與HandlerMapping與HandlerAdaper的部分,時序圖圖如下:

引用

http://jinnianshilongnian.iteye.com/blog/1602617

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.