Spring MVC HttpMessageConverter 的作用是什么?

HttpMessageConverter (HTTP 消息转换器) 是 Spring MVC 框架中一个非常核心的组件,它的主要作用是在 HTTP 请求、响应体与 Java 对象之间进行双向转换。

核心作用:

  1. 读取请求体 (Request Body) 到 Java 对象:

    • 当 Controller 方法的参数使用 @RequestBody 注解时,Spring MVC 会尝试找到一个合适的 HttpMessageConverter 来读取 HTTP 请求体的内容 (例如,JSON 或 XML 字符串),并将其反序列化 (deserialize) 成方法参数指定的 Java 对象类型。
    • 例如,一个 POST 请求发送了 JSON 数据 { "name": "John", "age": 30 },如果 Controller 方法参数是 @RequestBody User user,那么某个 HttpMessageConverter (如 MappingJackson2HttpMessageConverter) 会负责将这个 JSON 转换为一个 User 对象。
  2. 将 Java 对象写入响应体 (Response Body):

    • 当 Controller 方法使用 @ResponseBody 注解 (或者 Controller 类使用 @RestController 注解) 标记时,Spring MVC 会尝试找到一个合适的 HttpMessageConverter 来将方法的返回值 (通常是一个 Java 对象) 序列化 (serialize) 成特定格式 (例如,JSON 或 XML 字符串),并将其写入 HTTP 响应体。
    • 例如,一个 Controller 方法返回一个 User 对象,如果内容协商确定应该返回 JSON,那么某个 HttpMessageConverter 会将 User 对象转换为 JSON 字符串并发送给客户端。

它是如何实现自动转换的 (特别是 JSON/XML)?

这个自动转换过程涉及到以下几个关键步骤和组件:

  1. 注册 HttpMessageConverter 实例:

    • Spring MVC (在 Spring Boot 环境下,通常是自动) 会在应用启动时初始化并注册一个 HttpMessageConverter 列表。
    • 这些转换器是针对不同数据格式的,例如:
      • MappingJackson2HttpMessageConverter: 用于 JSON 格式的转换,它底层使用 Jackson 库。
      • Jaxb2RootElementHttpMessageConverter: 用于 XML 格式的转换,它底层使用 JAXB (Java Architecture for XML Binding)。
      • MappingJackson2XmlHttpMessageConverter: 也是用于 XML,但使用 Jackson 的 XML 模块。
      • StringHttpMessageConverter: 用于纯文本字符串。
      • ByteArrayHttpMessageConverter: 用于字节数组。
      • 还有其他用于表单数据、Protobuf 等的转换器。
    • Spring Boot 会根据类路径上的依赖自动配置这些转换器。例如,如果 jackson-databind 在类路径上,MappingJackson2HttpMessageConverter 就会被自动注册。
  2. 内容协商 (Content Negotiation) 确定目标媒体类型:

    • 对于响应 (对象 -> 响应体):
      • Spring MVC 通过 ContentNegotiationManager 来确定应该返回给客户端的媒体类型 (MIME type)。
      • 它会考虑:
        • Controller 方法上 @RequestMapping (或其变体) 的 produces 属性。
        • 客户端请求的 Accept HTTP 头。
        • URL 路径扩展名 (如 .json, .xml) 或 URL 参数 (如 ?format=json) (如果配置了这些策略)。
      • 一旦确定了目标媒体类型 (例如 application/json)。
    • 对于请求 (请求体 -> 对象):
      • Spring MVC 会查看请求的 Content-Type HTTP 头,以了解请求体中的数据是什么格式 (例如 application/json)。
  3. 选择合适的 HttpMessageConverter

    • 对于响应:
      • Spring MVC 会遍历已注册的 HttpMessageConverter 列表。
      • 对于每个转换器,它会调用其 canWrite(Class<?> clazz, MediaType mediaType) 方法。
      • canWrite 方法会检查该转换器是否能够将给定的 Java 对象类型 (clazz,即 Controller 方法的返回值类型) 序列化为之前内容协商确定的目标媒体类型 (mediaType)。
      • 找到第一个返回 true 的转换器,就用它来进行转换。
    • 对于请求:
      • Spring MVC 同样会遍历已注册的 HttpMessageConverter 列表。
      • 对于每个转换器,它会调用其 canRead(Class<?> clazz, MediaType mediaType) 方法。
      • canRead 方法会检查该转换器是否能够将请求的 Content-Type (mediaType) 反序列化为 Controller 方法参数的目标 Java 对象类型 (clazz)。
      • 找到第一个返回 true 的转换器,就用它来进行转换。
  4. 执行转换 (序列化/反序列化):

    • 对于响应 (使用选定的转换器的 write 方法):
      • 调用选定转换器的 write(T t, MediaType contentType, HttpOutputMessage outputMessage) 方法。
      • t 是 Controller 返回的 Java 对象。
      • contentType 是协商好的响应媒体类型。
      • outputMessage 提供了写入 HTTP 响应体的方式。
      • JSON 示例 (使用 MappingJackson2HttpMessageConverter):
        • Jackson 的 ObjectMapper 会被用来将 Java 对象序列化为 JSON 字符串。
        • 这个 JSON 字符串会被写入到 HttpOutputMessage 的输出流中。
      • XML 示例 (使用 Jaxb2RootElementHttpMessageConverter):
        • JAXB 的 Marshaller 会被用来将带有 JAXB 注解的 Java 对象序列化为 XML 字符串。
        • 这个 XML 字符串会被写入到输出流中。
    • 对于请求 (使用选定的转换器的 read 方法):
      • 调用选定转换器的 read(Class<? extends T> clazz, HttpInputMessage inputMessage) 方法。
      • clazz 是 Controller 方法参数的目标 Java 对象类型。
      • inputMessage 提供了读取 HTTP 请求体的方式。
      • JSON 示例 (使用 MappingJackson2HttpMessageConverter):
        • Jackson 的 ObjectMapper 会从 HttpInputMessage 的输入流中读取 JSON 数据。
        • 然后将 JSON 数据反序列化为指定 clazz 类型的 Java 对象。
      • XML 示例 (使用 Jaxb2RootElementHttpMessageConverter):
        • JAXB 的 Unmarshaller 会从输入流中读取 XML 数据。
        • 然后将 XML 数据反序列化为指定 clazz 类型的 (带有 JAXB 注解的) Java 对象。

简而言之,整个过程可以概括为:

  1. 配置阶段: 注册一系列支持不同媒体类型的 HttpMessageConverter
  2. 请求处理阶段 (读取请求体):
    • 获取请求的 Content-Type
    • 根据 Content-Type 和目标对象类型,选择一个 HttpMessageConverter
    • 使用该转换器将请求体内容(如JSON/XML)反序列化为Java对象。
  3. 响应处理阶段 (写入响应体):
    • 通过内容协商确定响应的 Content-Type
    • 根据返回对象类型和协商好的 Content-Type,选择一个 HttpMessageConverter
    • 使用该转换器将Java对象序列化为响应体内容(如JSON/XML)。

开发中如果我们需要支持新的数据格式,只需要实现并注册一个新的 HttpMessageConverter 即可。

相关推荐
我是Superman丶几秒前
【Lua】java 调用redis执行 lua脚本
java·开发语言·junit
素雪风华5 分钟前
构建RAG混合开发---PythonAI+JavaEE+Vue.js前端的实践
java·vue.js·python·ai·语言模型·llms·qwen千问大模型
zm14 分钟前
服务器连接多客户端
java·javascript·算法
残花月伴24 分钟前
springCloud/Alibaba常用中间件之Setinel实现熔断降级
spring·spring cloud·中间件
Warren981 小时前
Java面试八股Spring篇(4500字)
java·开发语言·spring boot·后端·spring·面试
晚秋大魔王1 小时前
OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——gnutls
java·开发语言
胡子发芽1 小时前
面试题:请解释Java中的垃圾回收机制(Garbage Collection, GC),并讨论不同的垃圾回收算法及其优缺点
java·jvm
下雨天u1 小时前
maven dependencyManagement标签作用
java·数据库·maven
顾子茵2 小时前
c++从入门到精通(四)--动态内存,模板与泛型编程
java·开发语言·c++
码农飞哥2 小时前
互联网大厂Java求职面试实战:Spring Boot到微服务全景解析
java·spring boot·微服务·maven·hibernate·技术栈·面试技巧