我们来详细了解一下 HandlerMapping 在 Spring MVC 中的角色和工作机制。
一、 HandlerMapping 的核心职责
HandlerMapping 的核心职责是根据传入的 HTTP 请求信息,查找并确定应该由哪个处理器(Handler)来处理这个请求。
具体来说,它负责:
- 请求映射 (Request Mapping): 检查请求的各种属性,如 URL 路径、HTTP 方法 (GET, POST 等)、请求参数、请求头 (Headers)、媒体类型 (Content-Type, Accept) 等。
- 处理器查找 (Handler Lookup): 在应用程序中所有已注册的潜在处理器(通常是 Controller 类中的方法)中,根据预定义的映射规则(例如
@RequestMapping注解中的配置),找到与当前请求最匹配的那一个处理器。 - 返回处理器执行链 (HandlerExecutionChain): 如果找到了匹配的处理器,
HandlerMapping不仅仅返回处理器本身,还会将其与应用于该处理器的拦截器 (HandlerInterceptor) 封装在一起,形成一个HandlerExecutionChain对象,然后将这个对象返回给DispatcherServlet。拦截器链包含了处理器执行前后需要执行的通用逻辑。 - 处理无匹配处理器的情况: 如果根据请求信息找不到任何匹配的处理器,
HandlerMapping会通知DispatcherServlet(通常是返回null),DispatcherServlet随后会决定如何处理(例如返回 404 Not Found)。
可以把 HandlerMapping 想象成应用程序的“路由表”查询服务。 DispatcherServlet 拿着一个请求过来问:“嘿,这个请求该交给谁处理?” HandlerMapping 就负责查表并告诉 DispatcherServlet:“这个请求应该由 X Controller 的 Y 方法处理,并且在处理前后需要经过 A、B 这两个拦截器。”
二、 HandlerMapping 如何找到处理请求的 Controller 方法?
HandlerMapping 查找 Controller 方法的过程取决于其具体的实现类。以最常用的 RequestMappingHandlerMapping(处理 @RequestMapping 及其变体注解)为例,其大致工作流程如下:
-
初始化阶段 (应用启动时):
RequestMappingHandlerMapping会扫描 Spring 应用上下文中所有标记了@Controller或@RestController注解的 Bean。- 对于每个找到的 Controller Bean,它会进一步检查其中所有标记了
@RequestMapping(或@GetMapping,@PostMapping等) 注解的方法。 - 对每个标记了注解的方法,它会解析注解中定义的映射信息(URL 路径模式、HTTP 方法、参数条件、头条件、 consumes/produces 媒体类型等)。
- 将这些映射信息与对应的
HandlerMethod对象(包含了 Controller Bean 实例和具体的方法引用)关联起来,并存储在一个内部的数据结构中(可以想象成一个高效的查找表或注册表,例如使用 Map 或更复杂的树状结构来优化路径匹配)。这个过程建立了请求模式和处理方法之间的映射关系。
-
请求处理阶段 (运行时):
- 当
DispatcherServlet调用HandlerMapping的getHandler()方法,并传入当前的HttpServletRequest时: RequestMappingHandlerMapping会从请求中提取关键信息,主要是 URL 路径 和 HTTP 方法。- 它使用请求的 URL 路径去匹配初始化阶段构建的映射注册表中存储的路径模式。这可能涉及到 Ant 风格的路径匹配(如
/users/*,/products/**/details)或更复杂的 URI 模板变量匹配(如/users/{userId})。 - 找到路径匹配的候选 Handler 后,它会进一步检查其他映射条件是否也满足,例如:
- 请求的 HTTP 方法 是否与注解中指定的
method属性匹配? - 请求中是否包含注解中
params属性指定的请求参数? - 请求头是否包含注解中
headers属性指定的请求头? - 请求的
Content-Type是否与注解中consumes属性指定的媒体类型匹配? - 请求的
Accept头是否与注解中produces属性指定的媒体类型匹配?
- 请求的 HTTP 方法 是否与注解中指定的
- 它会选择最佳匹配的那个
HandlerMethod。Spring MVC 有一套复杂的匹配规则来处理多个 Handler 都可能匹配同一个请求的情况(例如,更具体的路径模式优先于更通用的模式)。 - 一旦确定了最终的
HandlerMethod,RequestMappingHandlerMapping还会查找适用于该 Handler 的拦截器(这些拦截器通常是全局配置或针对特定路径模式配置的)。 - 最后,将找到的
HandlerMethod和适用的拦截器列表封装成HandlerExecutionChain返回给DispatcherServlet。
- 当
三、 常见的 HandlerMapping 实现
Spring MVC 提供了多种 HandlerMapping 实现,以支持不同的处理器定义和映射方式。以下是一些常见的实现(Spring Boot 通常会根据项目依赖和配置自动注册):
-
RequestMappingHandlerMapping(最常用):- 作用: 处理标记了
@RequestMapping(及其快捷方式@GetMapping,@PostMapping等) 注解的 Controller 方法。 - 特点: 目前Spring MVC 应用中最常用的是
HandlerMapping。它提供了非常灵活和强大的映射功能,支持 URI 模板、Ant 路径匹配、多种请求条件(方法、参数、头、媒体类型)等。
- 作用: 处理标记了
-
BeanNameUrlHandlerMapping:- 作用: 将请求的 URL 路径与 Spring 容器中定义的 Bean 的名称 进行匹配。
- 特点: 如果一个请求的 URL 是
/myController,这个HandlerMapping会查找容器中名为/myController的 Bean 作为 Handler。这是一种比较早期且相对简单的映射方式,现在不太常用。
-
SimpleUrlHandlerMapping:- 作用: 允许我们通过显式的配置(通常在 Spring 的 XML 或 Java 配置类中)来维护 URL 模式和 Handler Bean 之间的映射关系。
- 特点: 提供了比
BeanNameUrlHandlerMapping更灵活的配置方式,可以将任意 URL 模式映射到任意 Handler Bean,并且可以方便地为特定 URL 模式配置拦截器。常用于映射一些非注解驱动的 Handler 或框架自带的 Handler(如处理静态资源的ResourceHttpRequestHandler)。
-
WelcomePageHandlerMapping(Spring Boot 特有):- 作用: 用于处理根路径 (
/) 请求,并尝试查找并映射到静态欢迎页面(如index.html)。
- 作用: 用于处理根路径 (
-
HandlerMappingfor Functional Endpoints (Spring WebFlux & Spring MVC):- 作用: 支持 Spring 5 引入的函数式 Web 框架风格,处理通过
RouterFunction定义的路由规则。RouterFunctionMapping是其实现类。
- 作用: 支持 Spring 5 引入的函数式 Web 框架风格,处理通过
在Spring Boot Web 应用中,RequestMappingHandlerMapping 会被自动配置并作为主要的 HandlerMapping。如果我们定义了静态资源处理或使用了 Actuator 端点,SimpleUrlHandlerMapping 也可能被自动配置用于处理这些特定的 URL 模式。
在开发中我们不需要直接与 HandlerMapping 实现交互,只需要通过注解(如 @RequestMapping)或配置(如定义 RouterFunction Bean)来声明映射规则即可。DispatcherServlet 会自动使用注册的 HandlerMapping 来完成查找工作。
1094

被折叠的 条评论
为什么被折叠?



