Spring MVC:handlermapping

來源:互聯網
上載者:User

標籤:deb   log   擴充   turn   type   detail   imp   int   err   

HandlerMapping

    首先這是一個介面,也就是可擴充。它的作用就是根據不同的請求去匹配對應的Handler,也就是根據請求匹配一個要求處理常式。這個過程需要兩個步驟:第一步,需要將Handler註冊到HandlerMapping中;第二步,分析請求根據規則從登入的Handler中匹配到對應的Handler,即Controller。預設情況下,SpringMvc為我們提供了幾個預設的HandlerMapping的實現,通過優先順序的次序決定執行的順序。

HandlerMapping執行順序

    在基於Spring MVC的Web應用程式中,我們可以為DispatcherServlet提供多個Handler- Mapping供其使用。DispatcherServlet在選用HandlerMapping的過程中,將根據我們所指定的一系列HandlerMapping的優先順序進行排序,然後優先使用優先順序在前的HandlerMapping。如果當前的HandlerMapping能夠返回可用的Handler,DispatcherServlet則使用當前返回的Handler進行Web請求的處理,而不再繼續詢問其他的HandlerMapping。否則,DispatcherServlet將繼續按照各個HandlerMapping的優先順序進行詢問,直到擷取一個可用的Handler為止。

SimpleUrlHandlerMapping

     現在,通過這個實作類別,我們來看看handlerMapping是如何註冊和擷取handler的。

public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {          private final Map<String, Object> urlMap = new HashMap<String, Object>();        // 通過屬性配置URL到Bean名的映射      public void setMappings(Properties mappings) {          CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);      }        // 配置URL到Bean的映射      public void setUrlMap(Map<String, ?> urlMap) {          this.urlMap.putAll(urlMap);      }        public Map<String, ?> getUrlMap() {          return this.urlMap;      }        @Override      public void initApplicationContext() throws BeansException {          super.initApplicationContext();          // 初始化的時候註冊處理器          registerHandlers(this.urlMap);      }        protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {          // 如果配置的處理器映射為空白,則警告          if (urlMap.isEmpty()) {              logger.warn("Neither ‘urlMap‘ nor ‘mappings‘ set on SimpleUrlHandlerMapping");          }          else {              // 對於沒一個配置的URL到處理器的映射,如果URL不是以斜線(/)開頭,則追加斜線開頭,則註冊處理器              for (Map.Entry<String, Object> entry : urlMap.entrySet()) {                  String url = entry.getKey();                  Object handler = entry.getValue();                  // Prepend with slash if not already present.                  if (!url.startsWith("/")) {                      url = "/" + url;                  }                  // Remove whitespace from handler bean name.                  if (handler instanceof String) {                      handler = ((String) handler).trim();                  }                  registerHandler(url, handler);              }          }      }    }  

首先,它通過一個hashmap來儲存請求和controller的對應關係,也就是儲存註冊資訊。類都被Ioc容器管理者,HandlerMapping管理的是對應關係。其中key是http請求的path資訊,value可以是一個字串,或者是一個處理請求的HandlerExecutionChain,如果是String類型,則會將其視為Spring的bean名稱。在HandlerMapping對象的建立中,IoC容器執行了一個容器回調方法setApplicationContext,在這個方法中調用initApplicationContext方法進行初始化,各個子類可以根據需求的不同覆寫這個方法。關於handlerMap資訊的註冊就是在initApplicationContext方法中被執行的。
    取得Handler的方法在他的父類中,源碼如下:

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {      String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);              //尋找符合匹配規則的handler。可能的結果是HandlerExecutionChain對象或者是null      Object handler = lookupHandler(lookupPath, request);              //如果沒有找到匹配的handler,則需要處理下default handler      if (handler == null) {          // We need to care for the default handler directly, since we need to          // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.          Object rawHandler = null;          if ("/".equals(lookupPath)) {              rawHandler = getRootHandler();          }          if (rawHandler == null) {              rawHandler = getDefaultHandler();          }                      //在getRootHandler和getDefaultHandler方法中,可能持有的是bean name。          if (rawHandler != null) {              // Bean name or resolved handler?              if (rawHandler instanceof String) {                  String handlerName = (String) rawHandler;                  rawHandler = getApplicationContext().getBean(handlerName);              }              validateHandler(rawHandler, request);              handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);          }      }              //如果handler還是為空白,則拋出錯誤。      if (handler != null && this.mappedInterceptors != null) {          Set<HandlerInterceptor> mappedInterceptors =                  this.mappedInterceptors.getInterceptors(lookupPath, this.pathMatcher);          if (!mappedInterceptors.isEmpty()) {              HandlerExecutionChain chain;              if (handler instanceof HandlerExecutionChain) {                  chain = (HandlerExecutionChain) handler;              } else {                  chain = new HandlerExecutionChain(handler);              }              chain.addInterceptors(mappedInterceptors.toArray(new HandlerInterceptor[mappedInterceptors.size()]));          }      }      if (handler != null && logger.isDebugEnabled()) {          logger.debug("Mapping [" + lookupPath + "] to handler ‘" + handler + "‘");      }      else if (handler == null && logger.isTraceEnabled()) {          logger.trace("No handler mapping found for [" + lookupPath + "]");      }      return handler;  } 

介面定義

    看過了這些之後我們再回頭看看HandleraMapping介面的定義:

public interface HandlerMapping {     String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";     String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";     String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";     String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";     String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";     public abstract HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }

眼尖的同學可能就要說了,這個介面下取得handler的方法怎麼傳回值是HandlerExecutionChain而不是一個handler呢?HandlerExecutionChain這個類,從名字可以直觀的看得出,這個對象是一個執行鏈的封裝。熟悉Struts2的都知道,Action對象也是被層層攔截器封裝,這裡可以做個類比,說明SpringMVC確實是吸收了Struts2的部分設計思想。大家可以再看看源碼,太長了我就不貼了。從源碼中可以看出,一個實質執行對象,還有一堆攔截器。這不就是Struts2中的實現麼,SpringMVC沒有避嫌,還是採用了這種封裝。得到HandlerExecutionChain這個執行鏈(execution chain)之後,下一步的處理將圍繞其展開。至此,HandlerExecutionChain整個執行脈絡也就清楚了:在真正調用其handler對象前,HandlerInterceptor介面實作類別組成的數組將會被遍曆,其preHandle方法會被依次調用,然後真正的handler對象將被調用。
    小結:這裡主要的內容就是註冊和擷取的兩個過程,以及SpringMvc對handler的一些封裝。認真的讀讀源碼,就能很清晰的看到這個類的整個執行過程。加深對SpringMvc的執行過程的瞭解,感覺還是相當不錯的。

參考

http://blog.csdn.net/zhuojiajin/article/details/46292125

 

Spring MVC:handlermapping

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.