资讯专栏INFORMATION COLUMN

SpringMVC之源码分析--HandlerMapping(六)

BDEEFE / 3211人阅读

摘要:概述上一节我们分析了的初始化过程,即创建并注册,本章我们分析下的请求处理过程,即查找。本系列文章是基于。最后创建了群方便大家交流,可扫描加入,同时也可加我,共同学习共同进步,谢谢

概述

上一节我们分析了RequestMappingHandlerMapping的初始化过程,即创建并注册HandlerMehtod,本章我们分析下RequestMappingHandlerMapping的请求处理过程,即查找HandlerMethod。

本系列文章是基于Spring5.0.5RELEASE。

总体流程

因本节重点分析RequestMappingHandlerMapping处理请求方式,所以我们从请求到达前端控制器(DispatcherServlet)的doDispatch方法开始,之前的请求处理可参考https://segmentfault.com/a/1190000014712270

流程描述:

用户请求到达前端控制器DispatcherServlet.doDispatch方法

在doDispatch方法中调用本类的getHandler方法

getHandler方法调用HandlerMapping的getHandler方法

HandlerMapping.getHandler方法由抽象类AbstractHandlerMapping实现,故最终调用AbstracthandlerMapping.getHandler方法

在AbstractHandlerMapping的getHandler方法中调用钩子函数getHandlerInternal方法,该方法由子类AbstractHandlerMethodMapping实现

最终由AbstracthandlerMethodMapping.getHandlerInternal返回处理器方法即HandlerMethod

HandlerMethod代表查找到的处理请求Controller中的方法

返回给AbstractHandlerMapping,最终由其将处理器方法和拦截器组装成HandlerExectionChain对象返回

源码分析

DispatcherServlet

处理用户请求的方法到达doDispatch方法,源码如下:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // ... ...
    
    //查找请求的处理器
    mappedHandler = getHandler(processedRequest);
    if (mappedHandler == null) {
        // 未找到处理器时跑异常
        noHandlerFound(processedRequest, response);
        return;
    }

    // ... ...
}

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        // 迭代Spring支持的HandlerMapping,即我们配置或默认的HandlerMapping
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name "" + getServletName() + """);
            }
            // 查找请求的处理器HandlerExecutionChain,包括请求需要的拦截器
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

AbstractHandlerMethodMapping

提供查出处理器模板方法,具体实现由子类实现getHandlerInternal方法实现,代码如下:

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 子类需实现getHandlerInternal方法,本例中由AbstractHandlerMethodMapping实现
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // 如果handler是bean名字,则根据名字从上下文获取到处理类
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }
    // 返回请求处理的HandlerExecutionChain对象
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    // 对跨域的处理
    if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    return executionChain;
}

AbstractHandlerMethodMapping

本类主要提供创建并注册HandlerMethod以及查找HandlerMethod功能,处理用户请求时,源码如下:

/**
 * 实现父类(AbstractHandlerMapping)的钩子函数
 */
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 使用工具类UrlPathHelper,解析用户请求url
    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 + "]");
            }
        }
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

/**
 * 查找当前请求的处理器方法
 */
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    // 定义匹配到的matches集合,其内存放匹配到的Match对象
    List matches = new ArrayList<>();
    // 根据请求url查找出RequestMappingInfo对象
    List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        // 将查找到的RequestMappingInfo和处理器方法封装成Match对象存入到matches数组
        addMatchingMappings(directPathMatches, matches, request);
    }
    // 为查询到RequestMappingInfo时
    if (matches.isEmpty()) {
        // this.mappingRegistry.getMappings().keySet()--返回已注册所有的RequestMappingInfo
        // 查找到将RequestMappingInfo和处理器方法封装后存入matches数组
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }
    // 有匹配对象
    if (!matches.isEmpty()) {
        // 排序处理
        Comparator comparator = new MatchComparator(getMappingComparator(request));
        matches.sort(comparator);
        if (logger.isTraceEnabled()) {
            logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
        }
        // 取出Match,其封装了RequestMappingInfo和处理器方法
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            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 + "}");
            }
        }
        // 主要是往Request的Attribute区放了些东西,具体啥用我也不懂
        handleMatch(bestMatch.mapping, lookupPath, request);
        // 返回处理器方法HandlerMethod
        return bestMatch.handlerMethod;
    }
    else {
        // 未找到处理
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}
总结

本节对RequestMappingHandlerMapping处理用户请求时的整体流程及核心源码进行了分析,如有问题或建议大家可扫描下方二维码进群反馈,我会知无不言言无不尽,希望对大家有所帮助。

最后创建了qq群方便大家交流,可扫描加入,同时也可加我qq:276420284,共同学习、共同进步,谢谢!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69516.html

相关文章

  • SpringMVC源码分析--HandlerMapping(一)

    摘要:接口接口作用是将请求映射到处理程序,以及预处理和处理后的拦截器列表,映射是基于一些标准的,其中的细节因不同的实现而不相同。该参数是类型,作用是检查所有的映射解析器或使用或为的,默认为,即从上下文中检查所有的。 概述 在Spring MVC启动章节https://segmentfault.com/a/1190000014674239,介绍到了DispatcherServlet的onRef...

    ralap 评论0 收藏0
  • SpringMVC源码分析--HandlerMapping(五)

    摘要:概述通过前三章的分析,我们简要分析了和,但对拦截器部分做详细的分析,拦截器的加载和初始化是三个相同的部分。 概述 通过前三章的分析,我们简要分析了SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,但对拦截器部分做详细的分析,拦截器的加载和初始化是三个HandlerMapping相...

    nanchen2251 评论0 收藏0
  • SpringMVC源码分析--HandlerMapping(三)

    摘要:与类图对比,类继承自抽象类,其又继承自抽象类,再往上继承关系与一致。创建初始化上一章我们分析了的创建初始化过程,的创建初始化过程与一样,方法的入口在抽象类中的方法。至此,代码编写完毕。 概述 本节我们继续分析HandlerMapping另一个实现类BeanNameUrlHandlerMapping,从类的名字可知,该类会根据请求的url与spring容器中定义的bean的name属性值...

    fsmStudy 评论0 收藏0
  • SpringMVC源码分析--HandlerMapping(二)

    摘要:由于抽象类重写了父类的方法,所以此时会调用的方法,在该方法中通过调用父类的方法,该方法通过模板方法模式最终调到类的方法。分析该类间接实现了接口,直接实现该接口的是抽象类,映射与请求。 概述 在前一章https://segmentfault.com/a/1190000014901736的基础上继续分析,主要完成SimpleUrlHandlerMapping类的原理。 本系列文章是基于Sp...

    Imfan 评论0 收藏0
  • SpringMVC源码分析--HandlerMapping(四)

    摘要:默认支持该策略。以上是对的宏观分析,下面我们进行内部细节分析。整体流程一通过实现接口,完成拦截器相关组件的初始化调用类的方法。总结本文主要分析了的初始化过程,希望对大家有帮助。随着学习的深入,后面有时间在分析下期中涉及的关键,比如等等。 概述 本节我们继续分析HandlerMapping另一个实现类ReqeustMappingHandlerMapping,该类是我们日常开发中使用最多的...

    imccl 评论0 收藏0

发表评论

0条评论

BDEEFE

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<