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 (註解驅動核心)
└─ (其他方法級映射)
ApplicationContext、ServletContext 訪問adaptedInterceptors (全局)、mappedInterceptors (路徑映射)getHandler() 模板方法,委託 getHandlerInternal()HandlerExecutionChain,整合攔截器registerHandler() 註冊 URL → Handler 映射getHandlerInternal():根據請求路徑查找最佳匹配/user/*、/user/**、/user/{id}initApplicationContext() 調用 detectHandlers()determineUrlsForHandler()<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 映射,不掃描、不約定。
核心創新:映射粒度從「Controller 類」細化到「處理器方法」。
isHandler()getMappingForMethod()MappingRegistration,確保唯一性| 類別 | 核心職責 |
|---|---|
| AbstractHandlerMethodMapping | 定義初始化流程、請求匹配骨架、註冊管理 |
| RequestMappingInfoHandlerMapping | 使用 RequestMappingInfo 封裝映射條件、實現匹配比較器 |
| RequestMappingHandlerMapping | 解析 @Controller/@RequestMapping 註解、生成 RequestMappingInfo |
@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);
}
handlerMethods.get(lookupPath) O(1) 快速命中RequestMappingInfo,調用 getMatchingCondition(request)Comparator<RequestMappingInfo> 排序,選擇最精確匹配handleMatch() 緩存映射資訊到請求屬性patternsRequestCondition:URL 模式集合methodsRequestCondition:HTTP 方法限制 (GET/POST 等)paramsRequestCondition:請求參數條件headersRequestCondition:請求頭條件consumesRequestCondition:Content-Type 條件producesRequestCondition:Accept 條件customRequestCondition:自定義條件擴展點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;
}
@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 進階開發與問題排查的關鍵。