HandlerMapping/HandlerAdapter 与参数解析
结论先行:HandlerMapping 负责"找处理器"——把请求映射成 HandlerExecutionChain(HandlerMethod + 拦截器);HandlerAdapter 负责"调处理器"——屏蔽不同类型 handler 的差异,统一发起调用。注解时代的主角是 RequestMappingHandlerMapping + RequestMappingHandlerAdapter:前者启动时扫描 @Controller/@RequestMapping 建立 URL→方法映射表,后者真正执行方法,其中参数绑定由 HandlerMethodArgumentResolver 完成、返回值写回由 HandlerMethodReturnValueHandler 完成。
一、组件职责与常见实现
| 组件 | 职责 | 常见实现 |
|---|---|---|
| HandlerMapping | 请求 → handler + 拦截器链 | RequestMappingHandlerMapping(注解,默认)、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping |
| HandlerAdapter | 适配并调用各类 handler | RequestMappingHandlerAdapter(注解方法)、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 写结果"。