SpringMVC之HandlerMapping

334 阅读6分钟

关键类图

image.png

关键类和类成员

// 本期重点核心类,关于泛型T在代码分析会有讲解
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    // 内部维护 URL 和 controller类和方法
    private final MappingRegistry mappingRegistry = new MappingRegistry();
    
    
    // 映射注册类
    class MappingRegistry {  
         
        // 地址映射
        private final Map<T, MappingRegistration<T>> registry = new HashMap<>();  
        // 关键,此处的pathLookup 就是通过url地址查找对应的映射属性的
        private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();  
     }
     // 映射实体此处维护的是直达Controller中的方法
     static class MappingRegistration<T> {  
        
        // 留个疑问, 此处的泛型T 下文会有解释
        private final T mapping;  
        // 内部维护着controller中标注的@RequestMapping方法
        private final HandlerMethod handlerMethod;  
        // url地址
        private final Set<String> directPaths;  
  
      }
  
}

简单概述下类结构

RequestMappingHandlerMapping

继承关系

  • 继承RequestMappingInfoHandlerMapping
  • 间接继承AbstractHandlerMethodMapping<RequestMappingInfo>

解惑上文中的泛型T

  • 看完继承关系后可以确定 T --> RequestMappingInfo

RequestMappingInfo

  • 简单概述就是,在URL请求中要满足下方的复合条件
  • 更为直观的理解是,在具体选中哪种URL映射关系的匹配条件。
/**  
* Request mapping information. A composite for the following conditions:  
* <ol>  
* <li>{@link PathPatternsRequestCondition} with parsed {@code PathPatterns} or  
* {@link PatternsRequestCondition} with String patterns via {@code PathMatcher}  
* <li>{@link RequestMethodsRequestCondition}  
* <li>{@link ParamsRequestCondition}  
* <li>{@link HeadersRequestCondition}  
* <li>{@link ConsumesRequestCondition}  
* <li>{@link ProducesRequestCondition}  
* <li>{@code RequestCondition} (optional, custom request condition)  
* </ol>  
*  
* @author Arjen Poutsma  
* @author Rossen Stoyanchev  
* @since 3.1  
*/
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
    @Nullable  
    private final String name;  
  
    @Nullable  
    private final PathPatternsRequestCondition pathPatternsCondition;  
  
    @Nullable  
    private final PatternsRequestCondition patternsCondition;  
  
    private final RequestMethodsRequestCondition methodsCondition;  
  
    private final ParamsRequestCondition paramsCondition;  
  
    private final HeadersRequestCondition headersCondition;  
  
    private final ConsumesRequestCondition consumesCondition;  
  
    private final ProducesRequestCondition producesCondition;  
  
    private final RequestConditionHolder customConditionHolder;  
  
    private final int hashCode;  
  
    private final BuilderConfiguration options;
}

数据结构分析

image.png

举个例子,我的controller类

@RestController  
@RequestMapping("/user-manager")  
public class UserController {  
  
    @GetMapping("/user")  
    public UserVO user(Long userId) {  
    return new UserVO();  
    }  
}

对应的关系入下

image.png

上述算是整个URL映射的一个数据结构分析,下边真正开始源码解析

初始化一

org.springframework.beans.factory.InitializingBean接口

  • 解释下这个接口的能力
    • 在spring生命周期中 大体分为:实例化 -> 属性赋值 -> 初始化 -> 使用 —> bean销毁
    • 而InitializingBean接口就是在bean属性复制后,可以让我们对bean进行一个自定义的处理换句话说,也可以理解为在spirng属性复制后,我们做一个自己想要的init处理。
  • 此处AbstractHandlerMethodMapping实现了这个接口,也就是借助于初始化的回调做了自定义的初始化。
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    @Override  
    public void afterPropertiesSet() {
        initHandlerMethods();  
    }
    // 初始化所有的handlerMethods
    protected void initHandlerMethods() {
        // 循环执行所有满足条件的beanName
        for (String beanName : getCandidateBeanNames()) {  
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {  
                // 关键方法入口
                processCandidateBean(beanName);  
            }  
        }  
        // 算是个后置处理此处,AbstractHandlerMethodMapping一个方法,只打印了日志
        // RequestMappingHandlerMapping 也未做实现,直接跳过
        handlerMethodsInitialized(getHandlerMethods());  
    }
}
    // 处理复合条件的bean
    protected void processCandidateBean(String beanName) {  
        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.isTraceEnabled()) {  
            logger.trace("Could not resolve type for bean '" + beanName + "'", ex);  
            }  
        }  
        // 重点关注下 isHandler方法
        if (beanType != null && isHandler(beanType)) {  
            // 处理满足条件的bean,源码下方会解释。
            detectHandlerMethods(beanName);  
        }  
    }

    // RequestMappingHandlerMapping 重写了AbstractHandlerMethodMapping的方法
    // 看一眼就明白了。只要是类上标注了@Controller和@RequestMapping的注解的就返回true
    // 由于AnnotatedElementUtils.hasAnnotation()方法buff的加持
    // 例如@RestController也会被标记为返回为true的
    // 有兴趣的小伙伴可以看看@RestController注解其实也是引用了@Controller
    @Override  
    protected boolean isHandler(Class<?> beanType) {  
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||  
            AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));  
    }

上述代码总结

  • 借助于spring生命周期初始化的回调功能,可以知道RequestMappingHandlerMapping自定义初始化的方法入口。
  • RequestMappingHandlerMapping重写了isHandler()方法,挑选候选的bean进行,进行进一步加工。
  • AnnotatedElementUtils.hasAnnotation() get到了一个新的知识点,有兴趣的小伙伴可以看看学习下。

初始化一、进一步加工

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
    protected void detectHandlerMethods(Object handler) {  
        // 获取bean类型
        // 如果入参是String类型则通过obtainApplicationContext获取bean的类型,通过这种方式
        // 如果该bean没有加载到spring容器中会先进行bean化,然后在获取class
        // 否则直接获取class
        Class<?> handlerType = (handler instanceof String ?  
        obtainApplicationContext().getType((String) handler) : handler.getClass());  
          
        if (handlerType != null) {  
            // 会不会疑惑?
            // 明明上边已经获取了类的类型 Class<?>,为什么还要获取一遍?
            // 此处简单说下,因为上边直接调用的Object的getClass方法,如果该bean被cglib代理了
            // 那么上边获取的类的类型不是想要的类的类型,所以此处再次获取一遍
            // 有兴趣的朋友可以看看ClassUtils的方法。
            Class<?> userType = ClassUtils.getUserClass(handlerType); 
            // 方法映射map集合
            // 先说下数据结构,以免刚学习的朋友蒙蔽
            // 还是举个我们项目中controller的例子
            // map中的key:就是Controller方法中标注了@RequestMapping的方法(包涵派生注解比如@GetMapping等等)
            // map中的value:就是最开始说的RequestMappingInfo 
            // 下方有贴图,可以看下 ①
            Map<Method, T> methods = MethodIntrospector.selectMethods(userType,  
            (MethodIntrospector.MetadataLookup<T>) method -> {  
                try {  
                    // 获取mapping的映射方法 下边会有代码解释 ②
                    return getMappingForMethod(method, userType);  
                }  
                catch (Throwable ex) {  
                            throw new IllegalStateException("Invalid mapping on handler class [" +  
                    userType.getName() + "]: " + method, ex);  
                }  
            });  
            if (logger.isTraceEnabled()) {  
                logger.trace(formatMappings(userType, methods));  
            }  
            else if (mappingsLogger.isDebugEnabled()) {  
                mappingsLogger.debug(formatMappings(userType, methods));  
            }  
            // 将所有的methods经过处理后,进行注册
            methods.forEach((method, mapping) -> {  
                // 此处简单解释下有兴趣的朋友可以看看
                // 此处是将method的私有方法,经过反射后改成public
                // 也就是说你的controller方法 标记了@getmapping,如果方法是私有的改成public。
                // 为什么这么做?埋个伏笔。
                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);  
                // 注册 ④
                registerHandlerMethod(handler, invocableMethod, mapping);  
            });  
    }  
    // ②
    @Override  
    @Nullable  
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {  
        // 创建RequestMappingInfo 这个也就是上文map<Method,T>的 T
        // createRequestMappingInfo有一个关键的信息,下边会简单介绍下
        RequestMappingInfo info = createRequestMappingInfo(method);  ③
        // 下边就是组装RequestMappingInfo,不再细说了,有兴趣的朋友可以看看
        if (info != null) {  
            
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);  
            if (typeInfo != null) {  
                info = typeInfo.combine(info);  
            }  
            String prefix = getPathPrefix(handlerType);  
            if (prefix != null) {  
                info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);  
            }  
        }  
            return info;  
        }
    }
    
    // ③ 简单说下,就是只有方法上标注了@RequestMapping注解的才会创建 (派生注解也算,比如@GetMapping)
    @Nullable  
    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {  
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);  
        RequestCondition<?> condition = (element instanceof Class ?  
            getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));  
        return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);  
    }
    
    // AbstractHandlerMethodMapping的方法,注册 ④
    protected void registerHandlerMethod(Object handler, Method method, T mapping) {  
        this.mappingRegistry.register(mapping, handler, method);  
    }

    // AbstractHandlerMethodMapping.MappingRegistry#register
    // 嗨,终于走到最后一个方法了,该方法走完后也就呼应了上文的数据结构图。
    public void register(T mapping, Object handler, Method method) {  
        this.readWriteLock.writeLock().lock();  
        try {  
            // 此处的Method是jdk的,现在讲Method维护到HandlerMethod中
            HandlerMethod handlerMethod = createHandlerMethod(handler, method);  
            // 此处简单说下
            // 咱们在开发controller的时候 有时候一不小心写了两个一模一样的接口,
            // 此处的作用就是校验重复的接口
            validateMethodMapping(handlerMethod, mapping);  
              
            Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);  
            // 将url地址维护到pathLookup
            // 举个例子 path 就是开发中的 user/list 这种
            for (String path : directPaths) {  
                this.pathLookup.add(path, mapping);  
            }  
            // 基于name的映射 此处略过
            String name = null;  
            if (getNamingStrategy() != null) {  
                name = getNamingStrategy().getName(handlerMethod, mapping);  
                addMappingName(name, handlerMethod);  
            }  
            // cors 略过 其实就是有个注解@CrossOrigin 可以标注到类和方法上,有兴趣的可以自己看下
            CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);  
            if (corsConfig != null) {  
                corsConfig.validateAllowCredentials();  
                this.corsLookup.put(handlerMethod, corsConfig);  
            }  
            // 放入map集合中,上边有数据结构关系图
            this.registry.put(mapping,  
                new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));  
        } finally {  
            this.readWriteLock.writeLock().unlock();  
        }  
    }

代码①

image.png

总结下

  • 获取controller类和类中的所有满足条件的方法
  • 将URL提取出来放入MappingRegistry.pathLookup中,pathLookup是一个LinkedMultiValueMap类型的,key:url,value就是RequestMappingInfo
  • 最后将RequestMappingInfo当做key,放入MappingRegistry.registry的hashmap中,value就是MappingRegistration(RequestMappingInfo,handlerMethod,directPaths...)

初始化二-DispatcherServlet

  • DispatcherServlet在第一次访问时会触发九大组件的init方法,此处不细说,仅仅说下handlerMapping初始化做了什么
// org.springframework.web.servlet.DispatcherServlet#initHandlerMappings
private void initHandlerMappings(ApplicationContext context) {  
    this.handlerMappings = null;  
     // 默认是true
    if (this.detectAllHandlerMappings) {  
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.  
        // 找出所有实现了HandlerMapping的接口,我们此次分析的RequestMappingHandlerMapping也在其中
        Map<String, HandlerMapping> matchingBeans =  
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);  
        if (!matchingBeans.isEmpty()) {  
            this.handlerMappings = new ArrayList<>(matchingBeans.values());  
            // We keep HandlerMappings in sorted order.  
            // 因为做了下排序
            AnnotationAwareOrderComparator.sort(this.handlerMappings);  
        }  
    }  
    else { 
    // 如果detectAllHandlerMappings是false,则进行bean加载,效果是一样的。
        try {  
             HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);  
            this.handlerMappings = Collections.singletonList(hm);  
        }  catch (NoSuchBeanDefinitionException ex) {  
            // Ignore, we'll add a default HandlerMapping later.  
        }  
    }  
  
    // Ensure we have at least one HandlerMapping, by registering  
    // a default HandlerMapping if no other mappings are found.  
    if (this.handlerMappings == null) {  
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);  
        if (logger.isTraceEnabled()) {  
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +  
            "': using default strategies from DispatcherServlet.properties");  
        }  
    }  
  
    for (HandlerMapping mapping : this.handlerMappings) {  
        // 循环遍历mapping,只要有一个返回true就可以
        // 我们本次分析的RequestMappingHandlerMapping 此处返回的就是true
        // 至于是怎么设置的,有兴趣的朋友可以看下这个类
        // org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerMapping
        // 在一开始加载的时候就设置好了。
        if (mapping.usesPathPatterns()) { 
            // 这个布尔值的作用,其实就是判断是否将HttpServletRequest的getRequestURI的url地址缓存起来
            this.parseRequestPath = true;  
            break;  
        }  
    }  
}

mvc请求流程之HandlerMapping

数据结构

在mvc请求中匹配controller方法时起关键作用的一个类Match org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.Match image.png

doDispatch不是本期的重点,简单看下关于handlerMapping的关键方法

// DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
    HttpServletRequest processedRequest = request;  
    HandlerExecutionChain mappedHandler = null;  
    boolean multipartRequestParsed = false;  
  
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  
    try {  
        ModelAndView mv = null;  
        Exception dispatchException = null;  
  
        try {  
            processedRequest = checkMultipart(request);  
            multipartRequestParsed = (processedRequest != request);  
  
            // Determine handler for the current request.  
            // ① 通过HttpServletRequest获取HandlerExecutionChain
            mappedHandler = getHandler(processedRequest);  
            // 如果找不到,则进行noHandlerFound处理 
            if (mappedHandler == null) {  
                noHandlerFound(processedRequest, response);  
                return;  
            }  
  
            // Determine handler adapter for the current request.  
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  
            // Process last-modified header, if supported by the handler.  
            String method = request.getMethod();  
            boolean isGet = HttpMethod.GET.matches(method);  
            if (isGet || HttpMethod.HEAD.matches(method)) {  
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
                    return;  
                }  
            }  
            // HandlerInterceptor前置处理器
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
                return;  
            }  

            // Actually invoke the handler.  
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
  
            if (asyncManager.isConcurrentHandlingStarted()) {  
                return;  
            }  
  
            applyDefaultViewName(processedRequest, mv);  
            // HandlerInterceptor 后置处理器
            mappedHandler.applyPostHandle(processedRequest, response, mv);  
        }  catch (Exception ex) {  
            dispatchException = ex;  
        }  
    catch (Throwable err) {  
        // As of 4.3, we're processing Errors thrown from handler methods as well,  
        // making them available for @ExceptionHandler methods and other scenarios.  
        dispatchException = new NestedServletException("Handler dispatch failed", err);  
    }  
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
    }  
    catch (Exception ex) {  
        // HandlerInterceptor执行after方法
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);  
    }  
    catch (Throwable err) {  
        triggerAfterCompletion(processedRequest, response, mappedHandler,  
        new NestedServletException("Handler processing failed", err));  
    }  
    finally {  
        if (asyncManager.isConcurrentHandlingStarted()) {  
            // Instead of postHandle and afterCompletion  
            if (mappedHandler != null) {  
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  
            }  
       } else {  
            // Clean up any resources used by a multipart request.  
            if (multipartRequestParsed) {  
                 cleanupMultipart(processedRequest);  
             }  
        }  
    }  
}




    // ① 简单来说就是遍历所有实现了HandlerMapping接口的实现类。
    @Nullable  
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
        if (this.handlerMappings != null) {  
            for (HandlerMapping mapping : this.handlerMappings) {  
                // 此处我们只需关心实现类为RequestMappingHandlerMapping即可
                HandlerExecutionChain handler = mapping.getHandler(request);  
                if (handler != null) {  
                    return handler;  
                }  
            }  
        }  
        return null;  
    }
    
    
  

获取HandlerExecutionChain

  • 通过getHandlerInternal方法获取HandlerMethod
  • 然后调用getHandlerExecutionChain方法获取chain

    // org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
    @Override  
    @Nullable  
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        // 获取handler,返回体是,HandlerMethod ②
        Object handler = getHandlerInternal(request);  
        if (handler == null) {  
            handler = getDefaultHandler();  
        }  
        if (handler == null) {  
            return null;  
        }  
        // Bean name or resolved handler?  
        if (handler instanceof String) {  
            String handlerName = (String) handler;  
            handler = obtainApplicationContext().getBean(handlerName);  
        }  

        // Ensure presence of cached lookupPath for interceptors and others  
        if (!ServletRequestPathUtils.hasCachedPath(request)) {  
            initLookupPath(request);  
        }  
        // 生成HandlerExecutionChain
        // HandlerExecutionChain属性中包涵HandlerInterceptor的实现类,包括我们自定义的
        // 前提是满足规则的,此处不细讲
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);  

        if (logger.isTraceEnabled()) {  
            logger.trace("Mapped to " + handler);  
        }  
        else if (logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {  
            logger.debug("Mapped to " + executionChain.getHandler());  
        }  
        // cors不做细讲
        if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {  
            CorsConfiguration config = getCorsConfiguration(handler, request);  
            if (getCorsConfigurationSource() != null) {  
                CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);  
                config = (globalConfig != null ? globalConfig.combine(config) : config);  
            }  
            if (config != null) {  
                config.validateAllowCredentials();  
            }  
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);  
        }  

        return executionChain;  
    }

组装HandlerExecutionChain

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { 
        // 从上边代码可以看出handler的类型是HandlerMethod
        // 所以此处new HandlerExecutionChain(handler) 新建了一个HandlerExecutionChain
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?  
        (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));  
        // 将满足条件的HandlerInterceptor实现类加入HandlerExecutionChain中
        // HandlerInterceptor不在本次分析中略过
        // 不过此处可以看出,HandlerInterceptor是在此处加入进去的
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {  
             if (interceptor instanceof MappedInterceptor) {  
                 MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;  
                 if (mappedInterceptor.matches(request)) {  
                        chain.addInterceptor(mappedInterceptor.getInterceptor());  
                    }  
                }  
             else {  
                 chain.addInterceptor(interceptor);  
             }  
        }  
        return chain;  
    }

获取HandlerMethod

    // org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal
    // ② 
    @Override  
    @Nullable  
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {  
        // 拿到请求的URL 比如 user/list
        String lookupPath = initLookupPath(request);  
        this.mappingRegistry.acquireReadLock();  
        try {  
            // 通过url和request拿到HandlerMethod
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);  
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);  
        }  
        finally {  
            this.mappingRegistry.releaseReadLock();  
        }  
    }
    
    @Nullable  
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {  
        // 数据结构上边有贴图,最好看下数据结构
        List<Match> matches = new ArrayList<>(); 
        // 此处通过lookupPath也就是url地址获取RequestMappingInfo集合
        // 源码就一行代码就是return this.pathLookup.get(urlPath);
        // 前边初始化一的时候 我们提过的pathLookup 会维护一个键值对。
        List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);  
        if (directPathMatches != null) { 
            // 将满足要求的RequestMappingInfo放入matches集合中
            //RequestMappingInfo前文中提到过,这个info是一些匹配的规则
            addMatchingMappings(directPathMatches, matches, request);  
        }  
        if (matches.isEmpty()) {  
            addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);  
        }  
        if (!matches.isEmpty()) {  
            Match bestMatch = matches.get(0);  
            // 恕小弟无能无法复现满足matches大于1的
            if (matches.size() > 1) {  
                Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));  
                matches.sort(comparator);  
                bestMatch = matches.get(0);  
                if (logger.isTraceEnabled()) {  
                    logger.trace(matches.size() + " matching mappings: " + matches);  
                }  
                if (CorsUtils.isPreFlightRequest(request)) {  
                    for (Match match : matches) {  
                        if (match.hasCorsConfig()) {  
                            return PREFLIGHT_AMBIGUOUS_MATCH;  
                        }  
                    }  
                }  
                else {  
                    Match secondBestMatch = matches.get(1);  
                    if (comparator.compare(bestMatch, secondBestMatch) == 0) {  
                    Method m1 = bestMatch.getHandlerMethod().getMethod();  
                    Method m2 = secondBestMatch.getHandlerMethod().getMethod();  
                    String uri = request.getRequestURI();  
                    throw new IllegalStateException(  
                    "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");  
                    }  
                }  
            }  
            request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());  
            handleMatch(bestMatch.mapping, lookupPath, request); 
            // 最后MappingRegistration中维护的HandlerMethod返回
            return bestMatch.getHandlerMethod();  
        }  
        else {  
            return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);  
        }  
    }

关于handlerMapping分析到此结束

整体数据结构如下

image.png

如有不足支出请支出,文章将持续更改

作者的疑问点

  • matches什么时候大于1
  • HandlerExecutionChain为什么每一次都new,缓存起来应该可以
    • 我的理解动态植入HandlerInterceptor的缘故,比如白名单等问题