MessageConverter
1、请求体和响应体
请求和响应都有对应的body,而这个body就是需要关注的主要数据。
请求体
请求体与请求的查询参数或者表单参数是不同的,
请求体的表述一般就是一段字符串;
而查询参数可以看作url的一部分,这两个是位于请求报文的不同地方;
表单参数可以按照一定格式放在请求体中,也可以放在url上作为查询参数。总之可以把请求体看作客户端通过请求报文捎带的字符串。
响应体
响应体则是浏览器渲染页面的依据,对于一个普通html页面得响应,响应体就是这个html页面的源代码。
2、Accept 与 Content-Type
含义
Accept 表示客户端希望接收的响应 body 类型,服务器可根据此字段选择合适的结果表述。
Content-Type 代表客户端发送的 body 的数据类型。
请求体和响应体都是需要配合 Content-Type 头部使用的,这个头部主要用于说明 body 中的字符串是什么格式的,比如:text,json,xml 等。
对于请求报文,只有通过此头部,服务器才能知道怎么解析请求体中的字符串;
对于响应报文,浏览器通过此头部才知道应该怎么渲染响应结果,是直接打印字符串还是根据代码渲染为一个网页。
常见的媒体格式
1 | text/html # HTML格式 |
比如
- 表示希望接收的数据类型是 xml 格式,本次请求发送的数据的数据格式是 html。
1 | Accept:text/xml; |
- 表示的是希望接收数据格式的顺序 最好先是
application/xml
,不行的话使用application/json
。
1 | Accept application/xml,application/json |
- 接收任意类型。
1 | accept:*/*` |
- 一大段资源,在最后又加上了
*/*
:客户端支持这些类型,并指定了希望得到类型的优先级,如果没有,依次表达意愿。
1 | "Accept", "image/gif, image/jpeg, image/pjpeg, ... application/msword, */*", |
Accept/Content-Type 对于 Java
对于 HttpServletRequest 和 HttpServletResponse,可以分别调用 getInputStream 和 getOutputStream 来直接获取 body,但是获取到的仅仅只是一段字符串。对于 Java 来说,处理一个对象肯定比处理一个字符串要更方便得也更好理解,Accept 与 Content-Type 的作用就是进行类型之间的转换:
- 根据 Content-Type 头部,将 body 字符串转换为 java 对象;
- 反过来,根据 Accept 头部,将 java 对象转换客户端期望格式的字符串。
SpringMVC 提供了多种 MessageConverter,用户也可以自己扩展实现,框架启动的时候,会装载能支持的各种 MessageConverter,请求来的时候,根据上述设置依次查找本地是否有对应的 MessageConverter,如果找到就用找到的 MessageConverter 返回对应的类型数据。
3、HttpMessageConverter
HttpMessageConverter<T>
是 Spring 3.0 新添加的一个接口,负责将请求信息转换为一个T类型的对象,将T类型的对象输出为响应信息。其中read
和write
方法的参数分别有有HttpInputMessage
和HttpOutputMessage
对象,这两个对象分别代表着一次http通讯中的请求和响应部分。
1 | package org.springframework.http.converter; |
DispatcherServlet 默认装配 RequestMappingHandlerAdapter ,可以打断点查看默认装配的 HttpMessageConverter:
实现类 | 功能 | 读支持MediaType | 写支持MediaType |
---|---|---|---|
StringHttpMessageConverter | 数据与String类型的相互转换 | text/* |
text/plain |
ByteArrayHttpMessageConverter | 数据与字节数组的相互转换 | */* |
application/octet-stream |
FormHttpMessageConverter | 表单与MultiValueMap的相互转换 | application/x-www-form-urlencoded |
application/x-www-form-urlencoded |
SourceHttpMessageConverter | 数据与javax.xml.transform.Source的相互转换 | text/xml和application/xml |
text/xml和application/xml |
MarshallingHttpMessageConverter | 使用Spring的Marshaller/Unmarshaller转换xml数据 | text/xml和application/xml |
text/xml和application/xml |
MappingJackson2HttpMessageConverter | 使用Jackson的ObjectMapper转换Json数据 | application/json |
application/json |
MappingJackson2XmlHttpMessageConverter | 使用Jackson的XmlMapper转换xml数据 | application/xml |
application/xml |
BufferedImageHttpMessageConverter | 数据与java.awt.image.BufferedImage的相互转换 | Java I/O API支持的所有类型 |
Java I/O API支持的所有类型 |
4、MessageConverter 的调用
对于消息转换器的调用,都是在 RequestResponseBodyMethodProcessor 类中完成的。它实现了HandlerMethodArgumentResolver 和 HandlerMethodReturnValueHandler 两个接口,分别实现了处理参数和处理返回值的方法。

(⬇折叠代码块)
1 | /** |
(⬇折叠代码块)
1 | /** |
爷爷类中AbstractMessageConverterMethodArgumentResolver 的 readWithMessageConverter 方法会循序遍历所有HttpMessageConverter,调用其 canRead()
方法, 若返回true表示可以处理,一旦有某个HttpMessageConverter可以处理某一请求的参数MediaType,就用这个HttpMessageConverter的 read()
方法读取参数;
一旦处理完数据即将返回,又用同样的方法遍历HttpMessageConverter列表, 找出第一个 canWrite()
返回true的HttpMessageConverter,调用其 write()
方法返回给客户端。
5、HttpMessageConverter 初始化
寻找子类RequestResponseBodyMethodProcessor构造方法的调用者,会发现处理器适配器 RequestHandlerMapping 使用了该方法,从中可以找到 MessageConverter list 的来源。
- 在ApplicationContextrefresh期间,HttpMessageConverter开始初始化,初始化分别在三个类中进行:其中RequestMappingHandlerAdapter和HttpMessageConvertersAutoConfiguration是同时行的互不干扰,HttpMessageConverters的初始化需要在前两个类初始化完成后才能进行;
- RequestMappingHandlerAdapter初始化默认HttpMessageConverter列表
- 调用所有WebMvcConfigurer类型的自定义配置类(@Configuration)的configureMessageConverters方法初始化 HttpMessageConverter列表;
- 如果没有自定义的WebMvcConfigurer配置,调用addDefaultHttpMessageConverters方法初始化HttpMessageConverter列表,默认HttpMessageConverter列表都是根据ClassLoader中是否加载否一个特定类来判断某一个HttpMessageConverter是否需要加到默认列表中,并且在最后做了一下排序,仅仅是把xml类型的转换器放到了目前的HttpMessageConverter列表最后;
- 调用所有WebMvcConfigurer类型的自定义配置类的extendMessageConverters方法扩展HttpMessageConverter列表,直接加在列表尾部
- HttpMessageConvertersAutoConfiguration类将所有HttpMessageConverter类型的组件(@Conponent/@Bean等),初始化到一个有上下文提供的 HttpMessageConverter列表中;
- HttpMessageConverters初始化时,将2和3两个列表合并,如果上下文提供的和默认列表中有重复但对象并非是同一个,会把上下文提供的HttpMessageConverter和默认列表中的HttpMessageConverter放在相邻的位置,并且会把上下文提供的放在前面;把所有上下文提供的且不在默认列表中的HttpMessageConverter放在整个合并列表的最前面,上下文提供的HttpMessageConverter顺序由类上的
@Order(value=1)
注解指定,value值越小越靠前,优先级越高。
RequestMappingHandlerAdapter 的构造方法
在初始化的时候会向存储 HttpMessageConverter 的列表 messageConverters 中添加各种类型的消息转换器。
1 | private List<HttpMessageConverter<?>> messageConverters; // 成员变量之一 |
(⬇折叠代码块)
1 | /** |
流程:https://blog.csdn.net/qq_40244391/article/details/102808162
源码、自定义:https://www.jianshu.com/p/2f633cb817f5 、https://blog.csdn.net/w522301629/article/details/81128630
初始化、加载、时序图:https://blog.csdn.net/CL_YD/article/details/103938905
-------------Thanks for your time.-------------