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

Spring MVC HandlerMapping 核心架構全景解析:從介面到註解驅動的演進

     編輯:Java 相關知識

前言

HandlerMapping 是 Spring MVC 請求分發的核心組件,負責將 HTTP 請求映射到對應的處理器。本文系統梳理 HandlerMapping 的繼承體系、核心介面契約、五大實現類別特點,以及註解驅動映射的實現原理。

核心介面契約

public interface HandlerMapping {
    /**
     * 根據請求獲取處理器執行鏈
     * @return HandlerExecutionChain (包含 handler + 攔截器鏈)
     */
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

繼承體系全景

HandlerMapping (介面)
  ↑
AbstractHandlerMapping (抽象基類)
  ├─ AbstractUrlHandlerMapping (URL 映射基類)
  │   ├─ AbstractDetectingUrlHandlerMapping (掃描檢測基類)
  │   │   ├─ BeanNameUrlHandlerMapping
  │   │   ├─ ControllerBeanNameHandlerMapping
  │   │   └─ ControllerClassNameHandlerMapping
  │   └─ SimpleUrlHandlerMapping (配置式映射)
  └─ AbstractHandlerMethodMapping (方法級映射基類)
      ├─ RequestMappingInfoHandlerMapping
      │   └─ RequestMappingHandlerMapping (註解驅動核心)
      └─ (其他方法級映射)

各層級職責劃分

1. AbstractHandlerMapping - 基礎設施層

  • 提供 ApplicationContext、ServletContext 訪問
  • 管理攔截器:adaptedInterceptors (全局)、mappedInterceptors (路徑映射)
  • 實現 getHandler() 模板方法,委託 getHandlerInternal()
  • 封裝 HandlerExecutionChain,整合攔截器

2. AbstractUrlHandlerMapping - URL 映射註冊與查找

  • 提供 registerHandler() 註冊 URL → Handler 映射
  • 實現 getHandlerInternal():根據請求路徑查找最佳匹配
  • 支援 Ant 路徑模式:/user/*、/user/**、/user/{id}
  • 路徑變量提取與暴露

3. AbstractDetectingUrlHandlerMapping - 自動掃描註冊

  • 覆寫 initApplicationContext() 調用 detectHandlers()
  • 掃描容器中所有 Bean,調用 determineUrlsForHandler()
  • 子類實現具體 URL 確定策略 (Bean 名稱、類名、Controller 類型等)

4. SimpleUrlHandlerMapping - 純配置式映射

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/user/list">userController</prop>
            <prop key="/user/add">userController</prop>
        </props>
    </property>
</bean>

直接在 XML/JavaConfig 中聲明 URL → BeanName 映射,不掃描、不約定。

5. AbstractHandlerMethodMapping - 方法級映射基礎

核心創新:映射粒度從「Controller 類」細化到「處理器方法」。

  • 掃描 Bean,判斷 isHandler()
  • 提取方法級映射資訊 getMappingForMethod()
  • 註冊 MappingRegistration,確保唯一性
  • 請求時:直接匹配 → 條件匹配 → 排序選優 → 封裝結果

註解驅動映射:RequestMappingHandlerMapping 深度解析

1. 三層架構職責

類別核心職責
AbstractHandlerMethodMapping 定義初始化流程、請求匹配骨架、註冊管理
RequestMappingInfoHandlerMapping 使用 RequestMappingInfo 封裝映射條件、實現匹配比較器
RequestMappingHandlerMapping 解析 @Controller/@RequestMapping 註解、生成 RequestMappingInfo

2. 初始化關鍵步驟

@Override
public void afterPropertiesSet() {
    // 1. 初始化預設後綴模式
    super.afterPropertiesSet();
}

protected boolean isHandler(Class<?> beanType) {
    // 2. 判斷是否為處理器:類上有 @Controller 或 @RequestMapping
    return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class)
        || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class);
}

protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 3. 解析方法級 @RequestMapping,合併類級註解
    RequestMappingInfo info = createRequestMappingInfo(method, handlerType);
    // 合併類級映射條件
    RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
    return typeInfo.combine(info);
}

3. 請求匹配流程

  1. 直接路徑匹配:handlerMethods.get(lookupPath) O(1) 快速命中
  2. 條件匹配:遍歷所有 RequestMappingInfo,調用 getMatchingCondition(request)
  3. 最佳匹配選擇:使用 Comparator<RequestMappingInfo> 排序,選擇最精確匹配
  4. 結果封裝:handleMatch() 緩存映射資訊到請求屬性

4. RequestMappingInfo 核心屬性

  • patternsRequestCondition:URL 模式集合
  • methodsRequestCondition:HTTP 方法限制 (GET/POST 等)
  • paramsRequestCondition:請求參數條件
  • headersRequestCondition:請求頭條件
  • consumesRequestCondition:Content-Type 條件
  • producesRequestCondition:Accept 條件
  • customRequestCondition:自定義條件擴展點

HandlerExecutionChain 攔截器整合

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

    // 1. 全局攔截器
    chain.addInterceptors(getAdaptedInterceptors());

    // 2. 路徑映射攔截器
    String lookupPath = urlPathHelper.getLookupPathForRequest(request);
    for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
        if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
            chain.addInterceptor(mappedInterceptor.getInterceptor());
        }
    }
    return chain;
}

版本演進與最佳實踐

Spring 版本對應關係

  • Spring 2.5 以前:Controller 介面 + SimpleUrlHandlerMapping/BeanNameUrlHandlerMapping
  • Spring 2.5-3.x:@Controller + DefaultAnnotationHandlerMapping (已移除)
  • Spring 3.1+:RequestMappingHandlerMapping (當前標準)
  • Spring 5.3+:支援 WebFlux 函數式路由

生產環境配置建議

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        // 1. 關閉後綴模式匹配 (安全性)
        configurer.setUseSuffixPatternMatch(false);
        // 2. 關閉尾部斜杠匹配
        configurer.setUseTrailingSlashMatch(false);
    }

    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
        // 3. 自定義 URL 路徑匹配策略
        mapping.setPathMatcher(new AntPathMatcher());
        mapping.setUrlPathHelper(new UrlPathHelper());
        return mapping;
    }
}

總結

HandlerMapping 經歷了從「配置式」→「約定掃描式」→「註解驅動方法級」三代演進。現代 Spring MVC 以 RequestMappingHandlerMapping 為核心,通過 RequestMappingInfo 封裝豐富的映射條件,配合高效的匹配與排序算法,實現了靈活、高效的請求路由。理解其架構演進與核心原理,是掌握 Spring MVC 進階開發與問題排查的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved