HandlerMapping 与 HandlerAdapter:处理器映射原理
DispatcherServlet 把「哪个请求交给谁处理」与「怎么调用它」拆成两个接口:HandlerMapping 负责找处理器,HandlerAdapter 负责调用处理器。理解了这对接口,就理解了 Spring MVC 为什么能同时支持注解控制器、函数式路由、静态资源等多种风格。
HandlerMapping:请求 → 处理器
HandlerMapping 的职责是:给定 HttpServletRequest,返回 HandlerExecutionChain(处理器对象 + 一组 HandlerInterceptor)。多个 HandlerMapping 按 order 升序排队,谁先命中就用谁。
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
常见实现有:
| 实现 | 匹配依据 | 典型用途 |
|---|---|---|
| RequestMappingHandlerMapping | @RequestMapping 注解 | 注解控制器(主力) |
| SimpleUrlHandlerMapping | URL 路径注册表 | 静态资源、视图控制器 |
| BeanNameUrlHandlerMapping | Bean 名以 / 开头 | 传统 Controller Bean |
| RouterFunctionMapping | RouterFunction | WebFlux/函数式风格 |
| WelcomePageHandlerMapping | / | 欢迎页(Boot 常见) |
在 @EnableWebMvc 的默认装配里,注解映射排在前面,静态资源处理排在最后,因此「先注解、后兜底」。
HandlerExecutionChain:处理器 + 拦截器
HandlerMapping 返回的不是裸处理器,而是一条执行链,拦截器与处理器绑定在一起,方便 DispatcherServlet 统一执行 preHandle → 调用 → postHandle → afterCompletion(详见第 30 章)。
HandlerAdapter:怎么调用处理器
找到处理器后,DispatcherServlet 再找一个能支持它的 HandlerAdapter,调用其 handle 方法完成真正的执行。同样有多种适配器,各自对应一种处理器风格:
| 适配器 | 支持的处理器 | 做的事 |
|---|---|---|
| RequestMappingHandlerAdapter | @RequestMapping 方法(HandlerMethod) | 参数解析、校验、返回值处理 |
| HttpRequestHandlerAdapter | HttpRequestHandler | 直接读写 request/response |
| SimpleControllerHandlerAdapter | Controller 接口 | 传统 MVC Controller |
public interface HandlerAdapter {
boolean supports(Object handler); // 是否支持该处理器
ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception;
}
RequestMappingHandlerAdapter 的「内功」
注解方法之所以能一行行写参数(@RequestParam、@RequestBody、Model 等),是因为 RequestMappingHandlerAdapter 内部维护了两张表:
- HandlerMethodArgumentResolver 列表:按顺序为每个方法参数找能解析它的解析器(能解析 @PathVariable、@RequestBody、@ModelAttribute、HttpServletRequest 等)。
- HandlerMethodReturnValueHandler 列表:把返回值写成响应、拼进 Model 或转成 ModelAndView(@ResponseBody、ResponseEntity、视图名等各有一组处理器)。
这两张表都可通过 WebMvcConfigurer 的 addArgumentResolvers / addReturnValueHandlers 追加自定义实现,默认装配内容以官方文档为准。
它们如何协作
// 示意:DispatcherServlet 内部思路
HandlerExecutionChain chain = handlerMapping.getHandler(request); // 1. 找链
HandlerAdapter adapter = getHandlerAdapter(chain.getHandler()); // 2. 找适配器
chain.applyPreHandle(request, response); // 3. 前置
ModelAndView mv = adapter.handle(request, response, chain.getHandler()); // 4. 执行
chain.applyPostHandle(request, response, mv); // 5. 后置
HandlerMapping 决定「谁能接」,HandlerAdapter 决定「怎么调」,拦截器挂在执行链上负责「前后织入」。注解控制器能工作,本质是 RequestMappingHandlerMapping 与 RequestMappingHandlerAdapter 这对黄金搭档在起作用。