SpringMvc 將@RequestMapping註冊到HandlerMapping

整體思路

Spring Mvc通過HandlerMapping返回執行鏈。在Spring容器中有多中不同的HandlerMapping實現,其對應不同的映射配置方式。在使用@RequestMapping註解時,SpringMvc通過RequestMappingHandlerMapping類的Bean解析、註冊、緩存映射關係,並提供匹配執行鏈的功能。

RequestMappingHandlerMapping

 

1 解析 url-method 映射關係 思路

RequestMappingHandlerMapping實現了InitializingBean接口,在其初始化時執行afterPropertiesSet方法。在此方法中其遍歷ApplicationContext中所有Bean,通過反射判斷其類型Class上是否有@Controller@RequestMapping註解。

若Class上有此類註解說明這個Bean是Controller。則執行detectHandlerMethods(beanName)方法,反射(clazz.getMethods())並遍歷此Bean的Method[],通過反射method.getAnnotation(RequestMapping)判斷並獲取方法上標註的@RequestMapping配置信息。將@RequestMapping信息封裝成RequestMappingInfo,將此method封裝成HandlerMethod。註冊到RequestMappingHandlerMapping的mappingRegistry中。

 

2 註冊並緩存 url-method 映射關係

RequestMappingHandlerMapping中的mappingRegistry對象中成員變量:各種Map還有一個讀寫鎖。

mappingRegistry的各個主要變量

 

 

3 接收請求在RequestMappingHandlerMapping中查找返回映射

通過request的請求URL從urlLookup中找到對應RequestMappingInfo,再通過RequestMappingInfo在mappingLookup中找到HandlerMethod。HandlerMethod爲url對應的@RequestMapping標註執行方法。

 

解析註冊具體實現

WebConfig上使用了@EnableWebMvc註解,這個註解導入了DelegatingWebMvcConfiguration配置,在DelegatingWebMvcConfiguration的父類WebMvcConfigurationSupport創建了RequestMappingHandlerMapping。

@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
    RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
    //...省略屬性設置
    return mapping;
}

RequestMappingHandlerMapping加載@RequestMapping

我一開始也不知道創建RequestMappingHandlerMapping作用,後來看到它的類圖就明白加載過程。

 

 

RequestMappingHandlerMapping的父類實現了InitializingBean,那麼在初始化的時候就會調用afterPropertiesSet方法。看下父類afterPropertiesSet的實現:

@Override
public void afterPropertiesSet() {
    initHandlerMethods();
}

protected void initHandlerMethods() {
    if (logger.isDebugEnabled()) {
        logger.debug("Looking for request mappings in application context: " + getApplicationContext());
    }
    //detectHandlerMethodsInAncestorContexts默認false,所以是得到所有的beanNames
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
            BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
            getApplicationContext().getBeanNamesForType(Object.class));

    for (String beanName : beanNames) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            Class<?> beanType = null;
            try {
                beanType = getApplicationContext().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);
                }
            }
            //2. isHandler由子類實現
            if (beanType != null && isHandler(beanType)) {
                //3. 查找controller中有@RequestMapping註解的方法,並註冊到請求
                detectHandlerMethods(beanName);
            }
        }
    }
    //空方法
    handlerMethodsInitialized(getHandlerMethods());
}

afterPropertiesSet實現交給了initHandlerMethods,initHandlerMethods的執行流程如下:

  1. 得到所有的beanName
  2. 遍歷beanNames,調用isHandler判斷bean是不是一個controller,isHandler由子類實現,RequestMappingHandlerMapping的實現如下,判斷bean中有沒有Controller或RequestMapping
@Override
protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
            AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
  1. 查找controller中有@RequestMapping註解的方法,並註冊到請求容器中
protected void detectHandlerMethods(final Object handler) {
    //1. 得到controller真實類型
    Class<?> handlerType = (handler instanceof String ?
            getApplicationContext().getType((String) handler) : handler.getClass());
    final Class<?> userType = ClassUtils.getUserClass(handlerType);

    //3. 封裝所有的Method和RequestMappingInfo到Map中
    Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            new MethodIntrospector.MetadataLookup<T>() {
                @Override
                public T inspect(Method method) {
                    try {
                        //2. 根據方法上的@RequestMapping信息構建RequestMappingInfo
                        return getMappingForMethod(method, userType);
                    }
                    catch (Throwable ex) {
                        throw new IllegalStateException("Invalid mapping on handler class [" +
                                userType.getName() + "]: " + method, ex);
                    }
                }
            });

    if (logger.isDebugEnabled()) {
        logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
    }
    for (Map.Entry<Method, T> entry : methods.entrySet()) {
        Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
        T mapping = entry.getValue();
        //4. 將RequestMappingInfo註冊到請求容器中
        registerHandlerMethod(handler, invocableMethod, mapping);
    }
}

detectHandlerMethods是加載請求核心方法,執行流程如下:
(1) 得到controller真實類型,controller可能被代理
(2) 根據方法上的@RequestMapping信息構建RequestMappingInfo,由RequestMappingHandlerMapping實現。從代碼上可以看出,必須方法上聲明@RequestMapping,類上的@RequestMapping纔會生效。

@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    //1. 根據方法上的@RequestMapping創建RequestMappingInfo
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        //2. 查找類上是否有@RequestMapping,如果有則和方法上的組合
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
            info = typeInfo.combine(info);
        }
    }
    return info;
}
  1. 封裝所有的Method和RequestMappingInfo到Map中
  2. 將RequestMappingInfo註冊到請求容器中
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    this.mappingRegistry.register(mapping, handler, method);
}

這裏就不再分析register方法的實現過程,主要是根據handler,method封裝成HandlerMethod,再請求的時候會得到HandlerMethod,然後反射調用。



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章