首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring MVC 核心原理深度解析:HandlerMapping 與 HandlerExecutionChain 源碼詳解

     編輯:Java 綜合教學

Spring MVC 核心原理深度解析:HandlerMapping 與 HandlerExecutionChain 源碼詳解

Spring MVC 的請求分發核心在於 HandlerMapping 接口及其實現類,負責將 HTTP 請求映射到對應的處理器,並構建包含攔截器的 HandlerExecutionChain。本文基於源碼深入剖析這一流程。

一、AbstractHandlerMapping:統一入口與模板方法

AbstractHandlerMapping 實現 HandlerMapping,定義最終對外暴露的 getHandler() 方法,採用模板方法模式:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    Object handler = getHandlerInternal(request); // 1. 子類實現具體查找邏輯
    if (handler == null) {
        handler = getDefaultHandler(); // 2. 兜底預設處理器
    }
    if (handler == null) return null;
    if (handler instanceof String) { // 3. Bean 名稱轉實例
        handler = getApplicationContext().getBean((String) handler);
    }
    return getHandlerExecutionChain(handler, request); // 4. 封裝攔截器鏈
}

二、構建 HandlerExecutionChain:攔截器註冊邏輯

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain)
        ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
    chain.addInterceptors(getAdaptedInterceptors()); // 全局攔截器
    String lookupPath = urlPathHelper.getLookupPathForRequest(request);
    for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
        if (mappedInterceptor.matches(lookupPath, pathMatcher)) { // 路徑匹配的 MappedInterceptor
            chain.addInterceptor(mappedInterceptor.getInterceptor());
        }
    }
    return chain;
}

三、AbstractUrlHandlerMapping:URL 路徑匹配核心

繼承自 AbstractHandlerMapping,實現 getHandlerInternal():

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    Object handler = lookupHandler(lookupPath, request); // 核心匹配邏輯
    // ... 預設處理器兜底、路徑暴露屬性等
    return handler;
}

四、lookupHandler:精確匹配與 Ant 風格模式匹配

protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
    // 1. 精確匹配
    Object handler = this.handlerMap.get(urlPath);
    if (handler != null) return buildPathExposingHandler(handler, urlPath, urlPath, null);

    // 2. 模式匹配
    List<String> matchingPatterns = new ArrayList<>();
    for (String pattern : this.handlerMap.keySet()) {
        if (getPathMatcher().match(pattern, urlPath)) matchingPatterns.add(pattern);
    }
    if (!matchingPatterns.isEmpty()) {
        // 按優先級排序(最長路徑優先)
        Collections.sort(matchingPatterns, getPathMatcher().getPatternComparator(urlPath));
        String bestMatch = matchingPatterns.get(0);
        handler = this.handlerMap.get(bestMatch);
        // 提取 URI 模板變數
        String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);
        Map<String, String> uriTemplateVars = new LinkedHashMap<>();
        for (String p : matchingPatterns) {
            if (getPathMatcher().getPatternComparator(urlPath).compare(bestMatch, p) == 0) {
                uriTemplateVars.putAll(getUrlPathHelper().decodePathVariables(request,
                    getPathMatcher().extractUriTemplateVariables(p, urlPath)));
            }
        }
        return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVars);
    }
    return null;
}

五、buildPathExposingHandler:封裝路徑與變數攔截器

protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
    String pathWithinMapping, Map<String, String> uriTemplateVariables) {
    HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
    chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
    if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
        chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
    }
    return chain;
}

此方法將最佳匹配路徑、路徑內相對路徑、URI 模板變數通過攔截器暴露給後續處理器使用。

六、validateHandler:預留驗證擴展點

protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {
    // 預留給子類覆寫,預設為空實現
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved