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 注解注解控制器(主力)
SimpleUrlHandlerMappingURL 路径注册表静态资源、视图控制器
BeanNameUrlHandlerMappingBean 名以 / 开头传统 Controller Bean
RouterFunctionMappingRouterFunctionWebFlux/函数式风格
WelcomePageHandlerMapping/欢迎页(Boot 常见)

在 @EnableWebMvc 的默认装配里,注解映射排在前面,静态资源处理排在最后,因此「先注解、后兜底」。

HandlerExecutionChain:处理器 + 拦截器

HandlerMapping 返回的不是裸处理器,而是一条执行链,拦截器与处理器绑定在一起,方便 DispatcherServlet 统一执行 preHandle → 调用 → postHandle → afterCompletion(详见第 30 章)。

HandlerAdapter:怎么调用处理器

找到处理器后,DispatcherServlet 再找一个能支持它的 HandlerAdapter,调用其 handle 方法完成真正的执行。同样有多种适配器,各自对应一种处理器风格:

适配器支持的处理器做的事
RequestMappingHandlerAdapter@RequestMapping 方法(HandlerMethod)参数解析、校验、返回值处理
HttpRequestHandlerAdapterHttpRequestHandler直接读写 request/response
SimpleControllerHandlerAdapterController 接口传统 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 这对黄金搭档在起作用。

笔记加载中…