@ResponseBody 原理

@ResponseBody 用于将方法的返回值直接写入 HTTP 响应体中,而不是渲染视图。它的核心逻辑与 @RequestBody 类似,但方向相反:将 Java 对象转换为 HTTP 响应体内容。


1. @ResponseBody 的处理入口:RequestMappingHandlerAdapter

@ResponseBody 的处理同样由 RequestMappingHandlerAdapter 完成。在 invokeHandlerMethod 方法中,RequestMappingHandlerAdapter 会调用 ServletInvocableHandlerMethod 来执行目标方法,并处理返回值。

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    // 1. 创建 ServletInvocableHandlerMethod 对象
    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
    
    // 2. 设置返回值处理器(HandlerMethodReturnValueHandler)
    invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    
    // 3. 调用目标方法并处理返回值
    invocableMethod.invokeAndHandle(webRequest, mavContainer);
    
    // 4. 返回 ModelAndView(如果返回值是视图)
    return getModelAndView(mavContainer, modelFactory, webRequest);
}

2. 返回值处理的核心:HandlerMethodReturnValueHandler

HandlerMethodReturnValueHandler 是 Spring MVC 中用于处理方法返回值的接口。@ResponseBody 注解的处理由 RequestResponseBodyMethodProcessor 完成。

2.1 HandlerMethodReturnValueHandler 接口

public interface HandlerMethodReturnValueHandler {
    // 判断是否支持当前返回值类型
    boolean supportsReturnType(MethodParameter returnType);
    
    // 处理返回值
    void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}

2.2 RequestResponseBodyMethodProcessor 的实现

RequestResponseBodyMethodProcessor 不仅实现了 HandlerMethodArgumentResolver,还实现了 HandlerMethodReturnValueHandler,用于处理 @ResponseBody 注解。

public class RequestResponseBodyMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
    
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        // 判断方法是否带有 @ResponseBody 注解
        return returnType.hasMethodAnnotation(ResponseBody.class);
    }
    
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        
        // 1. 标记请求已处理,不需要视图渲染
        mavContainer.setRequestHandled(true);
        
        // 2. 获取 HttpServletResponse 对象
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
        
        // 3. 使用 HttpMessageConverter 将返回值写入响应体
        writeWithMessageConverters(returnValue, returnType, webRequest, response);
    }
}

3. 返回值写入响应体:HttpMessageConverter

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

  • MappingJackson2HttpMessageConverter:用于将对象转换为 JSON 字符串。
  • StringHttpMessageConverter:用于将字符串直接写入响应体。

3.1 writeWithMessageConverters 方法

protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
        NativeWebRequest webRequest, HttpServletResponse response) throws IOException {
    
    // 1. 获取请求和响应的媒体类型(Content-Type)
    HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
    HttpHeaders headers = new HttpHeaders();
    MediaType contentType = getContentType(request, response);
    
    // 2. 遍历所有的 HttpMessageConverter,找到支持当前返回值类型的转换器
    for (HttpMessageConverter<?> converter : this.messageConverters) {
        if (converter.canWrite(returnType.getParameterType(), contentType)) {
            // 3. 使用转换器将返回值写入响应体
            ((HttpMessageConverter<T>) converter).write(value, contentType, new ServletServerHttpResponse(response));
            return;
        }
    }
    
    // 4. 如果没有找到支持的转换器,抛出异常
    throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}

3.2 MappingJackson2HttpMessageConverterwrite 方法

以 JSON 数据为例,MappingJackson2HttpMessageConverter 会将 Java 对象转换为 JSON 字符串并写入响应体。

public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
    
    @Override
    protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException {
        // 使用 Jackson 的 ObjectMapper 将对象转换为 JSON 字符串
        objectMapper.writeValue(outputMessage.getBody(), object);
    }
}

4. 响应体的写入流程

  1. RequestMappingHandlerAdapter 调用目标方法后,获取返回值。
  2. RequestResponseBodyMethodProcessor 判断方法是否带有 @ResponseBody 注解。
  3. 如果带有 @ResponseBody 注解,则使用 HttpMessageConverter 将返回值转换为响应体内容。
  4. 将转换后的内容写入 HttpServletResponse 的响应体中。
  5. 标记请求已处理,跳过视图渲染。

5. 总结:@ResponseBody 的处理流程

  1. DispatcherServlet 接收到请求后,调用 RequestMappingHandlerAdapter
  2. RequestMappingHandlerAdapter 使用 RequestResponseBodyMethodProcessor 处理 @ResponseBody 注解的返回值。
  3. RequestResponseBodyMethodProcessor 使用 HttpMessageConverter 将返回值转换为响应体内容。
  4. 将转换后的内容写入 HttpServletResponse 的响应体中。
  5. 标记请求已处理,跳过视图渲染。

通过以上流程,Spring MVC 能够将方法的返回值直接写入 HTTP 响应体中,从而实现 RESTful 风格的 API 开发。

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