@RequestBody 原理

在Spring MVC中,DispatcherServlet 是核心的请求分发器,负责将请求分发给相应的处理器(Controller)。@RequestBody 注解用于将HTTP请求体中的数据绑定到方法的参数上。下面是对 DispatcherServlet@RequestBody 的源码分析


1. 请求参数处理的入口:DispatcherServlet

DispatcherServlet 是 Spring MVC 的核心,负责将请求分发给对应的处理器(Controller)。在 doDispatch 方法中,DispatcherServlet 会调用 HandlerAdapter 来处理请求。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 1. 获取处理器(Handler)
    HandlerExecutionChain mappedHandler = getHandler(request);
    
    // 2. 获取处理器适配器(HandlerAdapter)
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    // 3. 调用处理器适配器的 handle 方法
    ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
    
    // 4. 处理视图渲染等后续逻辑
    processDispatchResult(request, response, mappedHandler, mv, dispatchException);
}

2. 处理器适配器:RequestMappingHandlerAdapter

RequestMappingHandlerAdapter 是 Spring MVC 默认的处理器适配器,负责调用带有 @RequestMapping 注解的方法。它的核心方法是 invokeHandlerMethod,该方法会解析请求参数并调用目标方法。

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    // 1. 创建 ServletInvocableHandlerMethod 对象
    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
    
    // 2. 设置参数解析器(HandlerMethodArgumentResolver)
    invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    
    // 3. 调用目标方法
    invocableMethod.invokeAndHandle(webRequest, mavContainer);
    
    // 4. 返回 ModelAndView
    return getModelAndView(mavContainer, modelFactory, webRequest);
}

3. 参数解析的核心:HandlerMethodArgumentResolver

HandlerMethodArgumentResolver 是 Spring MVC 中用于解析方法参数的接口。@RequestBody 注解的处理由 RequestResponseBodyMethodProcessor 完成。

3.1 HandlerMethodArgumentResolver 接口

public interface HandlerMethodArgumentResolver {
    // 判断是否支持当前参数
    boolean supportsParameter(MethodParameter parameter);
    
    // 解析参数
    Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}

3.2 RequestResponseBodyMethodProcessor 的实现

RequestResponseBodyMethodProcessorHandlerMethodArgumentResolver 的实现类,专门用于处理 @RequestBody 注解。

public class RequestResponseBodyMethodProcessor implements HandlerMethodArgumentResolver {
    
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 判断参数是否带有 @RequestBody 注解
        return parameter.hasParameterAnnotation(RequestBody.class);
    }
    
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        
        // 1. 获取请求体内容
        Object arg = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
        
        // 2. 获取参数名称
        String name = Conventions.getVariableNameForParameter(parameter);
        
        // 3. 数据绑定和验证
        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
            if (arg != null) {
                validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors()) {
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }
        }
        
        return arg;
    }
}

4. 请求体内容的读取:HttpMessageConverter

RequestResponseBodyMethodProcessor 使用 HttpMessageConverter 将请求体内容转换为 Java 对象。常用的 HttpMessageConverter 包括:

  • MappingJackson2HttpMessageConverter:用于 JSON 数据的转换。
  • StringHttpMessageConverter:用于字符串的转换。

4.1 readWithMessageConverters 方法

protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
    
    // 1. 创建 HttpInputMessage 对象
    HttpInputMessage inputMessage = createInputMessage(webRequest);
    
    // 2. 遍历所有的 HttpMessageConverter,找到支持当前参数类型的转换器
    for (HttpMessageConverter<?> converter : this.messageConverters) {
        if (converter.canRead(paramType, inputMessage.getHeaders().getContentType())) {
            // 3. 使用转换器读取请求体内容并转换为 Java 对象(这里可以确定是哪个json工具,当项目比较乱时,可能不能直观确定究竟是fastjson还是jackson)
            return ((HttpMessageConverter<T>) converter).read(paramType, inputMessage);
        }
    }
    
    // 4. 如果没有找到支持的转换器,抛出异常
    throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}

4.2 MappingJackson2HttpMessageConverterread 方法

以 JSON 数据为例,MappingJackson2HttpMessageConverter 会将请求体中的 JSON 字符串转换为 Java 对象。

public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
    
    @Override
    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException {
        // 使用 Jackson 的 ObjectMapper 将 JSON 字符串转换为 Java 对象
        return objectMapper.readValue(inputMessage.getBody(), objectMapper.constructType(type));
    }
}

5. 数据绑定和验证

RequestResponseBodyMethodProcessor 中,解析完请求体内容后,会进行数据绑定和验证。

if (binderFactory != null) {
    // 1. 创建 WebDataBinder
    WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
    
    // 2. 验证数据
    if (arg != null) {
        validateIfApplicable(binder, parameter);
        if (binder.getBindingResult().hasErrors()) {
            throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
        }
    }
}

6. 总结:@RequestBody 的处理流程

  1. DispatcherServlet 接收到请求后,调用 RequestMappingHandlerAdapter
  2. RequestMappingHandlerAdapter 使用 RequestResponseBodyMethodProcessor 解析 @RequestBody 注解的参数。
  3. RequestResponseBodyMethodProcessor 使用 HttpMessageConverter 将请求体内容转换为 Java 对象。
  4. 如果启用了数据绑定和验证,会调用 WebDataBinder 进行数据验证。
  5. 最终,解析后的参数值会传递给 Controller 方法。

通过以上流程,Spring MVC 能够将 HTTP 请求体中的数据绑定到方法的 @RequestBody 参数上。

posted @   CyrusHuang  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示