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

概述

上一節咱們分析了RequestMappingHandlerMapping的初始化過程,即建立並註冊HandlerMehtod,本章咱們分析下RequestMappingHandlerMapping的請求處理過程,即查找HandlerMethod。前端

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

整體流程

因本節重點分析RequestMappingHandlerMapping處理請求方式,因此咱們從請求到達前端控制器(DispatcherServlet)的doDispatch方法開始,以前的請求處理可參考http://www.javashuo.com/article/p-njjdktrq-kw.html跨域

流程描述:數組

  • 用戶請求到達前端控制器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方法,源碼以下:app

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方法實現,代碼以下:ide

@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<Match> matches = new ArrayList<>();
    // 根據請求url查找出RequestMappingInfo對象
    List<T> 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<Match> 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,共同窗習、共同進步,謝謝!源碼分析

相關文章
相關標籤/搜索