springmvc源碼分析-HandlerMapping工作流程

之前的一篇HandlerMapping初始化流程,講述了HandlerMapping的初始化流程,本文就來看下HandlerMapping的工作流程,主要就是根據(jù)http請求查找到對應(yīng)的controller,還會加上一些攔截器,然后執(zhí)行攔截器與controller的方法。

springmvc的請求入口都是DispatcherServlet的doDispatch方法,方法內(nèi)部的這行代碼就是請求映射到handler處理邏輯

mappedHandler = getHandler(processedRequest);

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

getHandler中,循環(huán)容器的所有HandlerMapping,執(zhí)行mapping的getHandler,若不為null,說明匹配了。這里HandlerMapping的執(zhí)行順序就是通過mapping的order屬性指定的,這里返回的是HandlerExecutionChain 對象,因為會存在一些攔截器,在請求處理方法的前后加一些邏輯。

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    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);
    }

    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    
    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}

這個方法主要有3個步驟

  1. 根據(jù)request獲取到handler,若沒匹配上,會返回容器一個默認的handler
  2. 找到interceptor,封裝成HandlerExecutionChain 對象
  3. 若有跨域的相關(guān)配置,則加上跨域的攔截器

先看下第一個步驟

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//拿到請求的路徑  如:/student/getStudent
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

根據(jù)請求路徑和請求對象查找HandlerMethod對象

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        addMatchingMappings(directPathMatches, matches, request);
    }
//省略...
    if (!matches.isEmpty()) {
        Match bestMatch = matches.get(0);
        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)) {
                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();
                String uri = request.getRequestURI();
                throw new IllegalStateException(
                        "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
            }
        }
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        handleMatch(bestMatch.mapping, lookupPath, request);
        return bestMatch.handlerMethod;
    }
    else {
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

根據(jù)請求路徑去從map查找(上篇文章有詳細的描述),獲取匹配到的RequestMappingInfo列表。最終再拿到一個HandlerMethod對象。

找到HandlerMethod對象后,再查找interceptor,封裝成HandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    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;
}

添加interceptor時分判斷是否為MappedInterceptor,這種需要根據(jù)請求路徑做匹配,匹配上的才會添加,還有一種是通用的,每個請求都會加上的,比如ConversionServiceExposingInterceptor

獲取到HandlerExecutionChain后,會根據(jù)是否有跨域配置,若有的話,加上跨域的處理器

protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
        HandlerExecutionChain chain, @Nullable CorsConfiguration config) {

    if (CorsUtils.isPreFlightRequest(request)) {
        HandlerInterceptor[] interceptors = chain.getInterceptors();
        return new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
    }
    else {
        chain.addInterceptor(0, new CorsInterceptor(config));
        return chain;
    }
}

當(dāng)根據(jù)request拿到最終要執(zhí)行的HandlerExecutionChain后,在執(zhí)行具體的controller的方法前后,及方法執(zhí)行完畢后,會先執(zhí)行攔截器的幾個回調(diào)方法。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //省略.....
    try {
        ModelAndView mv = null;
        Exception dispatchException = null;
        try {
    //省略
//拿到HandlerExecutionChain對象
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }
//先執(zhí)行攔截器的preHandle方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 執(zhí)行具體controller的方法
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//執(zhí)行攔截器的postHandle方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        //執(zhí)行攔截器的afterCompletion方法
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
//即使有異常拋出,也會執(zhí)行攔截器的afterCompletion方法
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    }
    //省略
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容