HandlerMapping/HandlerAdapter 与参数解析

结论先行HandlerMapping 负责"找处理器"——把请求映射成 HandlerExecutionChain(HandlerMethod + 拦截器);HandlerAdapter 负责"调处理器"——屏蔽不同类型 handler 的差异,统一发起调用。注解时代的主角是 RequestMappingHandlerMapping + RequestMappingHandlerAdapter:前者启动时扫描 @Controller/@RequestMapping 建立 URL→方法映射表,后者真正执行方法,其中参数绑定由 HandlerMethodArgumentResolver 完成、返回值写回由 HandlerMethodReturnValueHandler 完成

一、组件职责与常见实现

组件职责常见实现
HandlerMapping请求 → handler + 拦截器链RequestMappingHandlerMapping(注解,默认)、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping
HandlerAdapter适配并调用各类 handlerRequestMappingHandlerAdapter(注解方法)、HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter
ArgumentResolver方法入参绑定@PathVariable/@RequestParam/@RequestBody/@RequestHeader/@ModelAttribute 等内建解析器
ReturnValueHandler返回值 → 模型/响应RequestResponseBodyMethodProcessor(@ResponseBody JSON 写回)等

二、参数解析主要流程

  • RequestMappingHandlerAdapter 收到请求后,遍历注册的 HandlerMethodArgumentResolver,找 supportsParameter 返回 true 的那个来 resolveArgument;
  • 内建解析器覆盖:@PathVariable(路径变量)、@RequestParam(查询/表单参数)、@RequestBody(HttpMessageConverter 反序列化)、@RequestHeader、@CookieValue、@ModelAttribute(表单绑定 POJO)以及 Servlet API 参数(request/response)等。
// 自定义参数解析器:解析 @CurrentUser 注解标注的参数(如当前登录用户)
public class CurrentUserResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter p) {
        return p.hasParameterAnnotation(CurrentUser.class)
                && User.class.isAssignableFrom(p.getParameterType());
    }
    @Override
    public Object resolveArgument(MethodParameter p, ModelAndViewContainer mav,
            NativeWebRequest webRequest, WebDataBinderFactory binder) {
        // 简化:从 Token/会话取出当前用户
        return SecurityHolder.currentUser();   // 实际从 request/ThreadLocal 获取
    }
}

// 注册到 MVC 配置(WebMvcConfigurer 实现类里)
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    resolvers.add(new CurrentUserResolver());
}

常见追问 / 记忆点

  • 追问 1:RequestMappingHandlerMapping 何时建映射?答:容器启动时 initHandlerMethods 扫描所有 Bean 中的 @Controller 方法,把 @RequestMapping 元数据注册成 URL→HandlerMethod 映射。
  • 追问 2:Mapping 与 Adapter 为什么拆开?答:单一职责 + 开放扩展——新增一种 handler 类型只需加 Adapter,DispatcherServlet 不用改。
  • 追问 3:自定义返回处理器怎么做?答:实现 HandlerMethodReturnValueHandler,再 addReturnValueHandlers 注册。
  • 记忆点:"Mapping 找方法、Adapter 调方法、Resolver 喂参数、ReturnValue 写结果"。
笔记加载中…