DispatcherServlet 请求响应

news/2025/2/1 22:46:02/文章来源:https://www.cnblogs.com/cyrushuang/p/18696555

主要是 @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 {@Overridepublic boolean supportsReturnType(MethodParameter returnType) {// 判断方法是否带有 @ResponseBody 注解return returnType.hasMethodAnnotation(ResponseBody.class);}@Overridepublic 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 {@Overrideprotected 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 开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/877704.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis之作用域和生命周期

弄清楚SqlSessionFactoryBuild,SqlSessionFactory,SqlSession的作用域和生命周期,可以避免高并发程序中的资源浪费 具体知识点看狂神的两张ppt就行了

CF856C 题解

很厉害的排列计数0 原题链接:luogu & CF 在任务清单里放了半年,今天终于做出来了 qwq,不得不写题解了。 1 能被 \(11\) 整除的数长什么样子?它的奇数位之和与偶数位之和应当模 \(11\) 同余。 我们不妨把一个数的价值定为从前往后奇数位之和减去偶数位之和模 \(11\) 的值…

人生不止于职业发展

0 你的问题,我知道! 工作意义是啥?职业发展在人生啥角色? 1 工作意义 农村人努力学习考上大学,得好工作,为逃离同村同龄人十几岁就工厂打工命运,过不凡人生,实现改命的唯一途径。毕业就进入自带光环的大厂,有份让所有亲戚羡慕的公司和薪水。我认为工作价值是让自己自立…

『Python底层原理』--CPython如何编译代码

前一篇我们介绍了CPython VM的运行机制,它基于一系列字节码指令来实现程序逻辑。 不过,Python字节码在完整描述代码功能上存在局限性,于是代码对象应运而生。像模块、函数这类代码块的执行,本质上就是对应代码对象的运行,代码对象涵盖了字节码、常量、变量名以及各类属性信…

MyBatis之jdbc属性外部配置

将jdbc数据库连接属性写在db.properties中,如图 然然后在配置文件中引入

25.2.1小记

Object类Object类中自带的toString和equals函数(默认比较管理者是否管理相同的对象,可以通过对子类函数的重构实现正常比较) // @Override//重写,编译器会默认构造类型检查public boolean equals(Object obj) {//向下造型CD cc = (CD)obj;return artist.equals(cc.artist…

“尝试一下挣钱的辛苦”之装师

我尝试了把我做的兽头卖出去,记录一下从孩子出生到找到妈咪领养的过程 因为没有太多预算,所以兽设没有找画师,我自己构思的;整个制作过程都要用到热熔胶,很容易烫到>_<(热熔胶——手作娘离不开的东西),梳理毛布也很让人头疼,弄得房间里都是毛毛,虽然但是,孩子…

“尝试一下挣钱的辛苦”

我尝试了把我做的兽头卖出去,记录一下从孩子出生到找到妈咪领养的过程 因为没有太多预算,所以兽设没有找画师,我自己构思的;整个制作过程都要用到热熔胶,很容易烫到>_<(热熔胶——手作娘离不开的东西),梳理毛布也很让人头疼,弄得房间里都是毛毛,虽然但是,孩子…

VScode使用插件open-in-browser在默认浏览器中打开html文件

1. vscode extension中搜索open in browser,并下载。 我下载的第一个2. 打开.html文件 alt+shift+b手动选择特定浏览器打开 alt+b用默认浏览器打开,如果没有设置默认浏览器,可能出现以下问题3. 配置默认浏览器 ctrl+shift+p打开command palette 输入settings.json,打开Open…

在MacOS上安装sqllite

参考教程 https://www.runoob.com/sqlite/sqlite-installation.html 1.下载sqllite安装包 https://www.sqlite.org/2025/sqlite-autoconf-3480000.tar.gz wget https://www.sqlite.org/2025/sqlite-autoconf-3480000.tar.gz tar -xvzf sqlite-autoconf-3480000.tar.gz cd sqlit…

【译】MongoDB EF Core 提供程序:有什么新功能?

原文 | Rishit, Luce 翻译 | 郑子铭 这是 Rishit Bhatia 和 Luce Carter 的客座文章。Rishit 是 MongoDB 的高级产品经理,专注于 .NET 开发人员体验,在进入产品管理部门之前,他已经使用 C# 工作多年。Luce 是 MongoDB 的开发倡导者、Microsoft MVP,热爱代码、阳光和学习。本…

06. 文件权限

一、文件属性Linux 系统是一个典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。为了保证系统的安全性,Linux 系统对不同的访问用户访问同一个文件(包括目录文件)的权限做了不同的规定。在 Linux 中,我们可以使用 ll 或者 ls -l 命令来显示一个文件的属性以及…