SpringMVC源码解析之HandlerMapping

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/heroqiang/article/details/81539836

阅读须知

  • Spring源码版本:4.3.8
  • 文章中使用/* */注释的方法会做深入分析

正文

HandlerMapping是Spring MVC中一个很重要的角色,用于注册和获取handler,在初始化阶段如果用户没有指定HandlerMapping,会默认添加两个默认的策略BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping,其中DefaultAnnotationHandlerMapping在Spring的3.2版本注解了@Deprecated,已经不推荐使用了,推荐使用RequestMappingHandlerMapping,首先我们来看一下BeanNameUrlHandlerMapping的层次结构:
这里写图片描述
我们发现它实现了ApplicationContextAware接口和ServletContextAware接口,我们之前分析过,在bean的创建的过程中会调用Aware接口的相关set方法将资源设置到bean中,BeanNameUrlHandlerMapping相关的方法都是在父类中实现:
WebApplicationObjectSupport:

public final void setServletContext(ServletContext servletContext) {
    if (servletContext != this.servletContext) {
        this.servletContext = servletContext;
        if (servletContext != null) {
            // 默认空实现,留给子类扩展
            initServletContext(servletContext);
        }
    }
}

对ServletContextAware接口的实现比较简单,就是为servletContext属性赋值。
ApplicationObjectSupport:

public final void setApplicationContext(ApplicationContext context) throws BeansException {
    if (context == null && !isContextRequired()) {
        this.applicationContext = null;
        this.messageSourceAccessor = null;
    }
    else if (this.applicationContext == null) {
        if (!requiredContextClass().isInstance(context)) {
            throw new ApplicationContextException(
                    "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
        }
        this.applicationContext = context;
        this.messageSourceAccessor = new MessageSourceAccessor(context);
        /* 子类扩展实现自定义初始化操作 */
        initApplicationContext(context);
    }
    else {
        if (this.applicationContext != context) {
            throw new ApplicationContextException(
                    "Cannot reinitialize with different application context: current one is [" +
                    this.applicationContext + "], passed-in one is [" + context + "]");
        }
    }
}

ApplicationObjectSupport:

protected void initApplicationContext(ApplicationContext context) throws BeansException {
    /* 子类扩展实现自定义初始化操作 */
    initApplicationContext();
}

AbstractDetectingUrlHandlerMapping:

public void initApplicationContext() throws ApplicationContextException {
    /* 调用父类的初始化方法 */
    super.initApplicationContext();
    /* 查找handler */
    detectHandlers();
}

AbstractHandlerMapping:

protected void initApplicationContext() throws BeansException {
    // 留给子类扩展增加拦截器,默认空实现
    extendInterceptors(this.interceptors);
    // 找到所有MappedInterceptor类型的bean添加到adaptedInterceptors中
    detectMappedInterceptors(this.adaptedInterceptors);
    // 将interceptors中的拦截器取出放入adaptedInterceptors
    // 如果是WebRequestInterceptor类型的拦截器
    // 需要用WebRequestHandlerInterceptorAdapter进行包装适配
    initInterceptors();
}

AbstractDetectingUrlHandlerMapping:

protected void detectHandlers() throws BeansException {
    if (logger.isDebugEnabled()) {
        logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
    }
    // 获取所有的beanName
    String[] beanNames = (this.detectHandlersInAncestorContexts ?
            BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
            getApplicationContext().getBeanNamesForType(Object.class));
    for (String beanName : beanNames) {
        /* 从beanName中获取url */
        String[] urls = determineUrlsForHandler(beanName);
        if (!ObjectUtils.isEmpty(urls)) {
            /* 注册handler */
            registerHandler(urls, beanName);
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
            }
        }
    }
}

BeanNameUrlHandlerMapping:

protected String[] determineUrlsForHandler(String beanName) {
    List<String> urls = new ArrayList<String>();
    if (beanName.startsWith("/")) {
        urls.add(beanName);
    }
    String[] aliases = getApplicationContext().getAliases(beanName);
    for (String alias : aliases) {
        if (alias.startsWith("/")) {
            urls.add(alias);
        }
    }
    return StringUtils.toStringArray(urls);
}

很简单,就是判断beanName或者alias别名是否以/开头,如果是就添加到返回结果的集合中。
AbstractUrlHandlerMapping:

protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
    Assert.notNull(urlPaths, "URL path array must not be null");
    for (String urlPath : urlPaths) {
        /* 注册handler */
        registerHandler(urlPath, beanName);
    }
}

AbstractUrlHandlerMapping:

protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
    Assert.notNull(urlPath, "URL path must not be null");
    Assert.notNull(handler, "Handler object must not be null");
    Object resolvedHandler = handler;
    if (!this.lazyInitHandlers && handler instanceof String) {
        String handlerName = (String) handler;
        if (getApplicationContext().isSingleton(handlerName)) {
            // 如果handler为String类型,则按照beanName的方式创建handler
            resolvedHandler = getApplicationContext().getBean(handlerName);
        }
    }
    Object mappedHandler = this.handlerMap.get(urlPath);
    if (mappedHandler != null) {
        if (mappedHandler != resolvedHandler) {
            // 如果url对应的已经注册的handler与当前handler不同,抛出异常
            throw new IllegalStateException(
                    "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
                    "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
        }
    }
    else {
        if (urlPath.equals("/")) {
            if (logger.isInfoEnabled()) {
                logger.info("Root mapping to " + getHandlerDescription(handler));
            }
            // 如果handler的beanName等于/,设置为root handler
            setRootHandler(resolvedHandler);
        }
        else if (urlPath.equals("/* ")) {
            if (logger.isInfoEnabled()) {
                logger.info("Default mapping to " + getHandlerDescription(handler));
            }
            // 如果handler的beanName等于/* ,设置为默认handler
            setDefaultHandler(resolvedHandler);
        }
        else {
            // 注册为普通handler
            this.handlerMap.put(urlPath, resolvedHandler);
            if (logger.isInfoEnabled()) {
                logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
            }
        }
    }
}

下面我们来看一下RequestMappingHandlerMapping类的层次结构:
这里写图片描述
我们发现同样实现了ServletContextAware和ApplicationContextAware,相关实现方法的处理逻辑也是一样的,两者有共同的父类AbstractHandlerMapping,不同的是,BeanNameUrlHandlerMapping覆盖了父类的initApplicationContext方法实现了handler的注册,RequestMappingHandlerMapping没有,但我们发现它实现了另外一个我们关心的接口InitializingBean,我们知道,Spring的创建bean的过程中会调用它的afterPropertiesSet方法,我们来看相关实现:
RequestMappingHandlerMapping:

public void afterPropertiesSet() {
    // 设置一些配置属性
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setUrlPathHelper(getUrlPathHelper());
    this.config.setPathMatcher(getPathMatcher());
    this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
    this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
    this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
    this.config.setContentNegotiationManager(getContentNegotiationManager());
    /* 调用父类的afterPropertiesSet方法 */
    super.afterPropertiesSet();
}

AbstractHandlerMethodMapping:

public void afterPropertiesSet() {
    /* 初始化handler方法 */
    initHandlerMethods();
}

AbstractHandlerMethodMapping:

protected void initHandlerMethods() {
    if (logger.isDebugEnabled()) {
        logger.debug("Looking for request mappings in application context: " + getApplicationContext());
    }
    // 获取所有的beanName
    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); // 获取beanName对应的class
            }
            catch (Throwable ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                }
            }
            /* 判断是否是handler */
            if (beanType != null && isHandler(beanType)) {
                /* 寻找handler方法 */
                detectHandlerMethods(beanName);
            }
        }
    }
    // 留给子类扩展对已经初始化完毕的handler做一些个性化的处理
    handlerMethodsInitialized(getHandlerMethods());
}

RequestMappingHandlerMapping:

protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
            AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

判断是否是handler的逻辑很简单,就是看类是否有@Controller注解或@RequestMapping注解。
AbstractHandlerMethodMapping:

protected void detectHandlerMethods(final Object handler) {
    // 获取handler的class类型
    Class<?> handlerType = (handler instanceof String ?
            getApplicationContext().getType((String) handler) : handler.getClass());
    // 获取用户定义的class,上面获取的class有可能是CGLIB动态代理生成的class(CGLIB生成的class名称中会有$$符号,判断名称中是否包含$$符号来确定是否是CGLIB生成的class),这样就需要获取它的父类
    final Class<?> userType = ClassUtils.getUserClass(handlerType);
    // 获取方法中的元数据并与方法构建映射
    Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            new MethodIntrospector.MetadataLookup<T>() {
                @Override
                public T inspect(Method method) {
                    try {
                        /* 获取方法的RequestMapping信息 */
                        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()) {
        // 获取userType的相关可调用方法(如果方法所属的类型是userType类型或者是它的父类,则选中方法,否则从userType的接口中根据方法的名称和参数列表尝试获取方法,以上都获取不到会最后尝试从代理类本身获取方法)
        // 并校验(如果选中的方法的代理类的private方法,并且是非静态的,则会抛出异常)
        Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
        T mapping = entry.getValue();
        /* 注册HandlerMethod */
        registerHandlerMethod(handler, invocableMethod, mapping);
    }
}

MethodIntrospector:

public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
    final Map<Method, T> methodMap = new LinkedHashMap<Method, T>();
    Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
    Class<?> specificHandlerType = null;
    if (!Proxy.isProxyClass(targetType)) {
        handlerTypes.add(targetType);
        specificHandlerType = targetType;
    }
    handlerTypes.addAll(Arrays.asList(targetType.getInterfaces()));
    for (Class<?> currentHandlerType : handlerTypes) {
        final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
        ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
            @Override
            public void doWith(Method method) {
                // 获取具体的方法,例如如果类实现了接口的方法,需要获取到具体实现类的方法
                Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
                T result = metadataLookup.inspect(specificMethod); /* 获取元数据,由调用时传入的匿名对象实现 */
                if (result != null) {
                    // 获取bridge方法
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                    if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
                        methodMap.put(specificMethod, result);
                    }
                }
            }
        }, ReflectionUtils.USER_DECLARED_METHODS);
    }
    return methodMap;
}

这里提到了bridge方法,bridge方法是jdk1.5引入泛型之后加入的特性,如果一个类继承了一个范型类或者实现了一个范型接口,那么编译器在编译这个类的时候就会生成一个叫做桥接方法的混合方法(混合方法简单的说就是由编译器生成的方法,方法上有synthetic修饰符), 这个方法用于范型的类型安全处理,用户一般不需要关心桥接方法,有兴趣的读者可以参考官方文档来了解相关内容,这里给出链接
RequestMappingHandlerMapping:

protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    /* 创建RequestMappingInfo */
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        /* 创建RequestMappingInfo */
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
            // 将根据类的注解创建的RequestMappingInfo与根据方法的注解的创建的RequestMappingInfo结合
            info = typeInfo.combine(info);
        }
    }
    return info;
}

RequestMappingHandlerMapping:

private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
    // 合并@RequestMapping注解信息,要合并父类或者实现的接口的注解信息
    // 并且加工注解了@AliasFor的注解的属性,用JDK动态代理生成代理类包装这些信息返回
    RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
    // 留给子类扩展自定义的请求条件,默认空实现
    RequestCondition<?> condition = (element instanceof Class ?
            getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
    // 将注解的属性信息封装到RequestMappingInfo对象中返回
    return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

接下来就是handler的注册了:
AbstractHandlerMethodMapping:

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    /* 注册 */
    this.mappingRegistry.register(mapping, handler, method);
}
public void register(T mapping, Object handler, Method method) {
    // 支持并发访问,用读写锁控制全局变量
    this.readWriteLock.writeLock().lock();
    try {
        // 将handler和method封装到HandlerMethod中
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        // 断言HandlerMethod的唯一性
        assertUniqueMethodMapping(handlerMethod, mapping);
        if (logger.isInfoEnabled()) {
            logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
        }
        // 放入缓存
        this.mappingLookup.put(mapping, handlerMethod);
        // 获取mapping中的路径信息,如/user/{id}/get
        List<String> directUrls = getDirectUrls(mapping);
        for (String url : directUrls) {
            // 放入缓存
            this.urlLookup.add(url, mapping);
        }
        String name = null;
        if (getNamingStrategy() != null) {
            // 生成name,例如UserController的getById方法会生成UC#getById,拼接类名的大写字符和方法名生成
            name = getNamingStrategy().getName(handlerMethod, mapping);
            // 添加名称和HandlerMethod的映射缓存
            addMappingName(name, handlerMethod);
        }
        // 初始化CORS配置
        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }
        // 放入缓存
        this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
    }
    finally {
        this.readWriteLock.writeLock().unlock();
    }
}

到这里,handler的注册就完成了,我们来看一下如何根据请求获取handler:
AbstractHandlerMapping:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    /* 根据request获取对应的handler */
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        // 没有获取到handler则使用默认的handler
        handler = getDefaultHandler();
    }
    if (handler == null) {
        // 如果默认的handler也为null,直接返回null
        return null;
    }
    if (handler instanceof String) {
        String handlerName = (String) handler;
        // 通过beanName的方式加载handler
        handler = getApplicationContext().getBean(handlerName);
    }
    /* 获取handler请求处理链 */
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    // 4.2版本提供了对CORS跨域资源共享的支持
    if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    return executionChain;
}

首先看一下BeanNameUrlHandlerMapping如果获取handler:
AbstractUrlHandlerMapping:

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    // 截取用于匹配的有效路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    /* 根据路径寻找handler */
    Object handler = lookupHandler(lookupPath, request);
    if (handler == null) {
        // 如果没有寻找到handler
        Object rawHandler = null;
        if ("/".equals(lookupPath)) {
            // 如果路径是/使用RootHandler进行处理
            rawHandler = getRootHandler();
        }
        if (rawHandler == null) {
            // 没有则使用默认的handler处理
            rawHandler = getDefaultHandler();
        }
        if (rawHandler != null) {
            if (rawHandler instanceof String) {
                String handlerName = (String) rawHandler;
                // 根据beanName加载handler
                rawHandler = getApplicationContext().getBean(handlerName);
            }
            validateHandler(rawHandler, request);
            /* 构建handler请求处理链 */
            handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
        }
    }
    if (handler != null && logger.isDebugEnabled()) {
        logger.debug("Mapping [" + lookupPath + "] to " + handler);
    }
    else if (handler == null && logger.isTraceEnabled()) {
        logger.trace("No handler mapping found for [" + lookupPath + "]");
    }
    return handler;
}

其中默认Handler和RootHandler的注册我们都在上面的分析中看到了。
AbstractUrlHandlerMapping:

protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    // 从上文填充的handlerMap中直接获取
    Object handler = this.handlerMap.get(urlPath);
    if (handler != null) {
        if (handler instanceof String) {
            String handlerName = (String) handler;
            // 如果handler为String类型则根据beanName的方式创建handler
            handler = getApplicationContext().getBean(handlerName);
        }
        validateHandler(handler, request);
        /* 构建handler请求处理链 */
        return buildPathExposingHandler(handler, urlPath, urlPath, null);
    }
    List<String> matchingPatterns = new ArrayList<String>();
    // 通配符匹配
    for (String registeredPattern : this.handlerMap.keySet()) {
        if (getPathMatcher().match(registeredPattern, urlPath)) {
            matchingPatterns.add(registeredPattern);
        }
        else if (useTrailingSlashMatch()) {
            if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
                matchingPatterns.add(registeredPattern +"/");
            }
        }
    }
    String bestMatch = null;
    Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
    // 排序获取最匹配的url
    if (!matchingPatterns.isEmpty()) {
        Collections.sort(matchingPatterns, patternComparator);
        if (logger.isDebugEnabled()) {
            logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
        }
        bestMatch = matchingPatterns.get(0);
    }
    if (bestMatch != null) {
        // 根据最匹配的url获取handler
        handler = this.handlerMap.get(bestMatch);
        if (handler == null) {
            if (bestMatch.endsWith("/")) {
                handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
            }
            if (handler == null) {
                throw new IllegalStateException(
                        "Could not find handler for best pattern match [" + bestMatch + "]");
            }
        }
        if (handler instanceof String) {
            String handlerName = (String) handler;
            // 如果handler为String类型则根据beanName的方式创建handler
            handler = getApplicationContext().getBean(handlerName);
        }
        // 校验handler,默认空实现,留给子类扩展
        validateHandler(handler, request);
        // 获取url匹配的部分,如/docs/* 和/docs/cvs/commit,匹配的部分就是cvs/commit
        String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);
        Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
        // 有可能有多个最匹配的url,确保所有这些都有正确的URI模板变量
        for (String matchingPattern : matchingPatterns) {
            if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
                Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
                Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
                uriTemplateVariables.putAll(decodedVars);
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
        }
        /* 构建handler请求处理链 */
        return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
    }
    // 没匹配到返回null
    return null;
}

AbstractUrlHandlerMapping:

protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
        String pathWithinMapping, Map<String, String> uriTemplateVariables) {
    // 构建HandlerExecutionChain
    HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
    // 添加两个拦截器,用于设置相关属性到request对象中
    chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
    if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
        chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
    }
    return chain;
}

下面我们来看一下RequestMappingHandlerMapping如何获取handler:
AbstractHandlerMethodMapping:

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 截取用于匹配的有效路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    if (logger.isDebugEnabled()) {
        logger.debug("Looking up handler method for path " + lookupPath);
    }
    this.mappingRegistry.acquireReadLock();
    try {
        /* 获取HandlerMethod */
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        if (logger.isDebugEnabled()) {
            if (handlerMethod != null) {
                logger.debug("Returning handler method [" + handlerMethod + "]");
            }
            else {
                logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }
        // 如果获取到的HandlerMethod中封装的handler是String类型
        // 要根据beanName的方式创建handler并封装到一个新的HandlerMethod中返回
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

AbstractHandlerMethodMapping:

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<Match>();
    // 根据url在之前注册的缓存中获取RequestMappingInfo信息
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        /* 添加到匹配的映射集合中 */
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // 没有匹配到,别无选择,只能尝试遍历所有的映射来匹配
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }
    if (!matches.isEmpty()) {
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
        // 用RequestMappingInfo中的compareTo方法进行比较做排序
        Collections.sort(matches, comparator);
        if (logger.isTraceEnabled()) {
            logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
                    lookupPath + "] : " + matches);
        }
        // 获取匹配值最高的
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            // 校验如果有两个以上的匹配值最高的Match抛出异常,不知道该用哪个
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
                        request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
            }
        }
        /* 处理匹配到的资源 */
        handleMatch(bestMatch.mapping, lookupPath, request);
        return bestMatch.handlerMethod;
    }
    else {
        // 没有任何匹配的处理,再次遍历所有RequestMappingInfo根据URL判断是否有可以匹配的,根据不匹配的内容抛出不同的异常
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

AbstractHandlerMethodMapping:

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
    for (T mapping : mappings) {
        // 获取request匹配的条件(如Header、Param等)并封装到RequestMappingInfo中
        T match = getMatchingMapping(mapping, request);
        if (match != null) {
            // 根据RequestMappingInfo获取缓存中对应的HandlerMethod一同封装到Match对象中
            matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
        }
    }
}

RequestMappingInfoHandlerMapping:

protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
    super.handleMatch(info, lookupPath, request);
    String bestPattern;
    Map<String, String> uriVariables;
    Map<String, String> decodedUriVariables;
    // 获取通配符uri,如/user/{id}/get
    Set<String> patterns = info.getPatternsCondition().getPatterns();
    if (patterns.isEmpty()) {
        bestPattern = lookupPath;
        uriVariables = Collections.emptyMap();
        decodedUriVariables = Collections.emptyMap();
    }
    else {
        bestPattern = patterns.iterator().next();
        // 获取url变量,如id --> 1
        uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
        // url解码
        decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
    }
    // 下面为将相关信息放入request对象中
    request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
    request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);
    if (isMatrixVariableContentAvailable()) {
        Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);
        request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);
    }
    if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
        Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
        request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
    }
}

最后找到请求匹配的拦截器加入到执行链中:
AbstractHandlerMapping:

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

到这里,handler的注册和获取就完成了。

猜你喜欢

转载自blog.csdn.net/heroqiang/article/details/81539836
今日推荐