SpringMvc 源碼解讀——AbstractHandlerMethodMapping系列

  • RequestMappingHandlerMapping繼承於RequestMappingInfoHandlerMapping繼承於AbstractHandlerMethodMapping,其中AbstractHandlerMethodMapping系列是將method做爲handler來使用的,好比@RequestMapping所註釋的方法就是這種handler。AbstractHandlerMethodMapping裏涉及的三個map。

/* java
private final Map<T,HandlerMethod> handlerMethods = new LinkedHashMap<T,HandlerMethod>();
private final MultiValueMap<String,T> urlMap = new LinkedMultiValueMap<String,T>();
private final MultiValueMap<String,HandlerMethod> nameMap = new LinkedMultiValueMap<String,HandlerMethod>();
*/java

  • handlerMethods:保存着匹配條件(也就是RequestCondition)和Handler Method的對應關係,
  • urlMap:保存着URL與匹配條件的對應關係,固然這裏的URL是pattern式的,可使用通配符,另外,這裏的map並非普通的map,而是MultiValueMap,這是一種一個key對應多個值的Map,其實它的value是一個list類型的值。MultiValueMap的定義以下:public interface MultiValueMap<K,V> extends Map<K,List<V>>,這裏的RequestCondition其實就是在@RequestMapping中註釋的內容。
  • nameMap:這個Map是Spring MVC4新增的,保存着name和HandlerMethod的對應關係,它使用的是MultiValueMap類型的Map,也就是說一個name能夠有多個HandlerMethod,這裏的name是使用HandlerMethodMappingNamingStrategy策略的實現類從HandlerMethod中解析出來,默認使用RequestMappingInfoHandlerMethodMappingNamingStrategy實現類,解析規則是:類名裏的大寫字母+「#」+方法名

app

  • AbstractHandlerMethodMapping系列的建立過程是:AbstractHandlerMethodMapping實現了InitializingBean接口,因此Spring容器會自動調用其afterPropertiesSet方法,afterPropertiesSet有交給initHandlerMethods方法完成具體的初始化。

/* Java
protected void initHandlerMethods() {this

if (logger.isDebugEnabled()) {
        logger.debug("Looking for request mappings in application context: " + getApplicationContext());
    }
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
            BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
            obtainApplicationContext().getBeanNamesForType(Object.class));

    for (String beanName : beanNames) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            Class<?> beanType = null;
            try {
                beanType = obtainApplicationContext().getType(beanName);
            }
            catch (Throwable ex) {
                // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                }
            }
            if (beanType != null && isHandler(beanType)) {
                detectHandlerMethods(beanName);
            }
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}

*/url

  • 首先拿到容器裏全部的bean,而後跟住必定的規則篩選出來Handler,而後保存在map裏,具體的篩選是在子類裏,篩選的邏輯是檢查類前是否有@Controller或者@RequestMapping註解。緊接着,在detectHandlerMethods負責將Handler保存在Map裏,detectHandlerMethods方法分兩步走:首先從傳入的處理器中找到符合要求的方法,而後用registerHandlerMethod進行註冊(也就是保存在Map中),從這裏能夠看出Spring實際上是將處理請求的方法所在的類看做處理器,而不是處理請求的方法,不過許多地方須要將請求的方法做爲處理器來理解。從handler裏獲取能夠處理請求的method的方法使用了HandlerMethodSelector.selectMethods,這個方法能夠遍歷傳入的handler的全部方法,而後根據第二個MethodFilter類型的參數篩選出來合適的方法,這裏的MethodFilter使用了匿名類,具體的判斷邏輯是經過在匿名類裏調用getMappingForMethod方法獲取Method的匹配條件,若是能夠獲取,則認爲是符合要求的,不然不符合要求,getMappingForMethod是模版方法,具體實如今RequestMappingHandlerMapping裏,它是根據@RequestMapping註解來【匹配條件的,若是沒有@RequestMapping註解則返回null,若是有,則根據註解的內容來建立RequestMappingInfo類型的匹配條件並返回。最後經過registerHandlerMethod的方法,註冊到map中,在該方法中,首先檢查一下handlerMethods這個map裏是否已經有這個匹配條件了,若是有並且所對應的值和如今傳入的handlerMethod不是同一個則拋出異常,否者依次添加到三個map裏,再往nameMap裏添加的時候須要現解析出name而後調用updateNameMap方法進行添加,經過put方法,進行覆蓋式添加。
相關文章
相關標籤/搜索