HttpMessageConverters 自动配置类源码解析 -HttpMessageConvertersAutoConfiguration
HttpMessageConverters 自动配置类源码解析 -HttpMessageConvertersAutoConfiguration
源码版本:spring-boot-autoconfigure-2.7.5.jar
源码分析
HttpMessageConverters
HttpMessageConverters 的作用是管理 Spring Boot 应用程序中使用的 HttpMessageConverters 的 Bean(不限于 Web 场景)。提供了一种方便的方法来添加和合并用户自定义的 HttpMessageConverter 到 web 应用程序中。
我们只需要声明
HttpMessageConverter类型的 bean(有需要的话可以通过@Order进行排序),就可以添加自定义的HttpMessageConverter,而在 SpringMVC 中,还需要重写configureMessageConverters或extendMessageConverters方法。SpringMVC 配置HttpMessageConverter的方式请看《SpringMVC- 第十篇:基于注解配置 SpringMVC.md》的configureMessageConverters & extendMessageConverters小节
我们可以在创建 HttpMessageConverters 实例的时候指定额外的、用户自定义的 HttpMessageConverter,否则只会使用默认的 HttpMessageConverter。
实际上,默认的
HttpMessageConverter为WebMvcConfigurationSupport#addDefaultHttpMessageConverters方法返回的HttpMessageConverter,获取之后,会稍微调一下顺序,将处理XML的HttpMessageConverter放到列表的最后面。也就是说,默认的
HttpMessageConverter,SpringBoot 跟 SpringMVC 一致,只是如果存在处理XML的HttpMessageConverter的话,默认的HttpMessageConverter的顺序可能稍微不一样。
源码中的核心点是 HttpMessageConverters 的构造函数,而在构造函数中,有两个方法比较核心,
-
HttpMessageConverters#getDefaultConverters:用于获取默认的HttpMessageConverter,实际上就是WebMvcConfigurationSupport#addDefaultHttpMessageConverters方法返回的HttpMessageConverter列表,如果不是 SpringMVC 环境,则使用RestTemplate#getMessageConverters方法返回的HttpMessageConverter列表。 -
HttpMessageConverters#getCombinedConverters,用于将用户自定义添加的HttpMessageConverter列表(大部分都是 IOC 容器中HttpMessageConverter类型的 bean)跟默认添加的HttpMessageConverter列表进行合并,根据类型将用户自定义添加的与默认添加的类型相同或为其子类的HttpMessageConverter放到最终HttpMessageConverter列表的前面。HttpMessageConverter列表中HttpMessageConverter的顺序很重要,代表HttpMessageConverter的优先级,排得越靠前,优先级越高。
public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>> {
// 初始化一个用户自定义添加的、在与系统默认的HttpMessageConverter合并时,不调整顺序(优先级)的 HttpMessageConverter,即 TypeConstrainedMappingJackson2HttpMessageConverter
private static final List<Class<?>> NON_REPLACING_CONVERTERS;
static {
List<Class<?>> nonReplacingConverters = new ArrayList<>();
addClassIfExists(nonReplacingConverters, "org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter");
NON_REPLACING_CONVERTERS = Collections.unmodifiableList(nonReplacingConverters);
}
// addClassIfExists
...
// 初始化一个系统默认添加的、在与用户自定义添加的HttpMessageConverter合并时,视为相同替换对象的 HttpMessageConverter,
// 即 系统默认添加了 MappingJackson2HttpMessageConverter ,但是用户没有自定义添加 MappingJackson2HttpMessageConverter 类型或MappingJackson2HttpMessageConverter的子类型的 HttpMessageConverter ,用户自定义添加的是 GsonHttpMessageConverter 或其子类,也要调整优先级 ,将用户自定义添加的 GsonHttpMessageConverter 放到前面去
private static final Map<Class<?>, Class<?>> EQUIVALENT_CONVERTERS;
static {
Map<Class<?>, Class<?>> equivalentConverters = new HashMap<>();
putIfExists(equivalentConverters, "org.springframework.http.converter.json.MappingJackson2HttpMessageConverter", "org.springframework.http.converter.json.GsonHttpMessageConverter");
EQUIVALENT_CONVERTERS = Collections.unmodifiableMap(equivalentConverters);
}
// putIfExists
...
// 核心字段,保存所有的 HttpMessageConverter
private final List<HttpMessageConverter<?>> converters;
// converters 的 getter 方法 和 converters的迭代器实现
......
// 参数缺省的构造函数
......
// 核心构造函数
public HttpMessageConverters(boolean addDefaultConverters, Collection<HttpMessageConverter<?>> converters) {
// 将用户自定义添加的 HttpMessageConverter 列表和 系统默认添加的 HttpMessageConverter 列表合并
List<HttpMessageConverter<?>> combined = getCombinedConverters(converters, addDefaultConverters ? getDefaultConverters() : Collections.emptyList());
// 对合并结果进行后置处理,postProcessConverters方法目前为空方法,是个钩子,方便子类重写,自定义业务逻辑
combined = postProcessConverters(combined);
// 赋值到 converters 属性
this.converters = Collections.unmodifiableList(combined);
}
// 获取系统默认添加的 HttpMessageConverter
private List<HttpMessageConverter<?>> getDefaultConverters() {
List<HttpMessageConverter<?>> converters = new ArrayList<>();
if (ClassUtils.isPresent("org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport", null)) {
// WebMvcConfigurationSupport 存在,表示是SpringMVC环境
// 这是匿名内部类的写法
converters.addAll(new WebMvcConfigurationSupport() {
// 匿名内部类添加 defaultMessageConverters 方法
public List<HttpMessageConverter<?>> defaultMessageConverters() {
// 匿名内部类实例的 defaultMessageConverters 方法实际上是委托给父类也就是 WebMvcConfigurationSupport的getMessageConverters方法
// 实际上在 WebMvcConfigurationSupport 中因为 configureMessageConverters 和 extendMessageConverters 都是空方法,
// 所以getMessageConverters方法最终返回的 其实就是 addDefaultHttpMessageConverters 方法。
return super.getMessageConverters();
}
}.defaultMessageConverters());
} else {
// 如果不是SpringMVC框架,那么就是添加 RestTemplate 中的 HttpMessageConverter
converters.addAll(new RestTemplate().getMessageConverters());
}
// 将 xml类的 messageConverter放到列表的末尾
reorderXmlConvertersToEnd(converters);
return converters;
}
private List<HttpMessageConverter<?>> getCombinedConverters(Collection<HttpMessageConverter<?>> converters, List<HttpMessageConverter<?>> defaultConverters) {
// 最终返回的 HttpMessageConverter 集合
List<HttpMessageConverter<?>> combined = new ArrayList<>();
// 用户自定义的,用来进行循环处理的 HttpMessageConverter 的集合
// 注意,下文中的迭代器中的 iterator.remove(); 操作,是会修改 processing 列表的值的
List<HttpMessageConverter<?>> processing = new ArrayList<>(converters);
for (HttpMessageConverter<?> defaultConverter : defaultConverters) {
Iterator<HttpMessageConverter<?>> iterator = processing.iterator();
while (iterator.hasNext()) {
HttpMessageConverter<?> candidate = iterator.next();
// 如果需要替换,则将用户自定义添加的HttpMessageConverter先添加到结果中,即优先级高于默认添加的的HttpMessageConverter
// isReplacement 方法的本质是判断是否进行顺序(优先级)的调整
if (isReplacement(defaultConverter, candidate)) {
combined.add(candidate);
iterator.remove();
}
}
// 将用户自定义的同类型或为子类的HttpMessageConverter添加完毕之后,再添加默认的HttpMessageConverter
// 即自定义的同类型或为子类的HttpMessageConverter比默认的HttpMessageConverter的优先级更高。
combined.add(defaultConverter);
if (defaultConverter instanceof AllEncompassingFormHttpMessageConverter) {
// AllEncompassingFormHttpMessageConverter 中也包含很多 HttpMessageConverter,也需要跟用户自定义添加的HttpMessageConverter进行混合(调序)
configurePartConverters((AllEncompassingFormHttpMessageConverter) defaultConverter, converters);
}
}
// 将剩下的自定义HttpMessageConverter放到最终结果列表的最前面。
combined.addAll(0, processing);
// 对HttpMessageConverter进行调序,本质上是调整优先级
return combined;
}
private boolean isReplacement(HttpMessageConverter<?> defaultConverter, HttpMessageConverter<?> candidate) {
// 如果用户自定义添加的 HttpMessageConverter 是 NON_REPLACING_CONVERTERS 中指定的类型,则不进行顺序(优先级)调整
for (Class<?> nonReplacingConverter : NON_REPLACING_CONVERTERS) {
if (nonReplacingConverter.isInstance(candidate)) {
return false;
}
}
// 如果自定义添加的 HttpMessageConverter 和 默认添加的HttpMessageConverter 是同一个类型,或者为其子类,则进行顺序(优先级)调整
Class<?> converterClass = defaultConverter.getClass();
if (ClassUtils.isAssignableValue(converterClass, candidate)) {
return true;
}
// 如果自定义添加的 HttpMessageConverter 和 默认添加的HttpMessageConverter 既不是同一个类型,也不为其子类,那就检查跟默认添加的 HttpMessageConverter 的类型等效的类型
// 如果 自定义添加的 HttpMessageConverter 是等效类型或其子类,则依然进行顺序(优先级)调整
Class<?> equivalentClass = EQUIVALENT_CONVERTERS.get(converterClass);
return equivalentClass != null && ClassUtils.isAssignableValue(equivalentClass, candidate);
}
private void configurePartConverters(AllEncompassingFormHttpMessageConverter formConverter,
Collection<HttpMessageConverter<?>> converters) {
List<HttpMessageConverter<?>> partConverters = formConverter.getPartConverters();
List<HttpMessageConverter<?>> combinedConverters = getCombinedConverters(converters, partConverters);
combinedConverters = postProcessPartConverters(combinedConverters);
formConverter.setPartConverters(combinedConverters);
}
// reorderXmlConvertersToEnd
......
// postProcessConverters 和 postProcessPartConverters ,都是 空方法
......
}
简单调试
合并结果的实践,其实主要就是实验 HttpMessageConverters#isReplacement 方法
注册三个 HttpMessageConverter 类型的 bean:MyMessageConverter0、MyMessageConverter1、MyResourceHttpMessageConverter
@Component
@Order(2)
public class MyMessageConverter0 implements HttpMessageConverter {
@Override
public boolean canRead(Class clazz, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Class clazz, MediaType mediaType) {
return false;
}
@Override
public List<MediaType> getSupportedMediaTypes() {
return null;
}
@Override
public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
}
}
@Component
@Order(1)
public class MyMessageConverter1 implements HttpMessageConverter {
@Override
public boolean canRead(Class clazz, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Class clazz, MediaType mediaType) {
return false;
}
@Override
public List<MediaType> getSupportedMediaTypes() {
return null;
}
@Override
public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
}
}
@Component
@Order(3)
public class MyResourceHttpMessageConverter extends ResourceHttpMessageConverter {
}
启动项目,在 HttpMessageConverters#getCombinedConverters 方法上打断点,可以看到:
用户自定义添加的 HttpMessageConverter 列表

可以看到除了我们自定义的三个 HttpMessageConverter 类型的 bean 之外,还有两个 HttpMessageConverter 类型的 bean,StringHttpMessageConverter 和 MappingJackson2HttpMessageConverter
关于这两个 bean 的添加,请看
HttpMessageConvertersAutoConfiguration小节
其中 MyMessageConverter1、MyMessageConverter0、MyResourceHttpMessageConverter 三个 HttpMessageConverter 类型的 bean 的顺序由 @Order 注解控制,其实 StringHttpMessageConverter 和 MappingJackson2HttpMessageConverter 这两个 bean 的顺序也是 @Order 注解控制的,因为这两个 bean 没有 @Order 注解修饰,所以默认放到组后面
关于
HttpMessageConverter类型的 bean 的顺序,具体请看HttpMessageConvertersAutoConfiguration小节
系统默认添加的 HttpMessageConverter 列表

可以注意到会有三个默认添加的 HttpMessageConverter 是自定义添加的 HttpMessageConverter 的父类或者同类型
-
ResourceHttpMessageConverter -
StringHttpMessageConverter -
MappingJackson2HttpMessageConverter
我们可以注意到,
MappingJackson2HttpMessageConverter不仅默认添加了,在自定义添加的HttpMessageConverter(大部分都是 IOC 容器中HttpMessageConverter类型的 bean)中也存在,于是导致了最终的HttpMessageConverter列表中有两个MappingJackson2HttpMessageConverter。具体原因看HttpMessageConvertersAutoConfiguration小节
这三个默认添加的 HttpMessageConverter 将和自定义添加的对应 HttpMessageConverter 交换顺序。
最终合并结果,默认添加 8 个,自定义添加 5 个,总共 13 个。

MyMessageConverter1 和 MyMessageConverter0 因为没有默认添加的 HttpMessageConverter 是其父类或者跟其类型相同,因此成为漏网之鱼,在 HttpMessageConverters#getCombinedConverters 方法的最后将其添加到了最终列表的最前面,自定义/额外添加的 MyResourceHttpMessageConverter、StringHttpMessageConverter、MappingJackson2HttpMessageConverter 与默认添加的、ResourceHttpMessageConverter、StringHttpMessageConverter、MappingJackson2HttpMessageConverter 对应,分别调整到对应 HttpMessageConverter 的前面。
HttpMessageConvertersAutoConfiguration
HttpMessageConvertersAutoConfiguration 的作用是自动配置 HttpMessageConverter
HttpMessageConvertersAutoConfiguration在《SpringBoot 基础篇 -2- 自动配置.md》中都提到过。
SpringMVC 配置
HttpMessageConverter的方式请看《SpringMVC- 第十篇:基于注解配置 SpringMVC.md》的configureMessageConverters & extendMessageConverters小节为什么到了 SpringBoot 之后,要将其改成通过 Bean 注册的方式来配置
HttpMessageConverter,我猜是因为HttpMessageConverter应用比较广泛,不仅限于 Web 场景,因此将其提取出来作为 bean 进行管理。
接下来进行简单的源码分析:
HttpMessageConvertersAutoConfiguration 本身注册了一个 HttpMessageConverters 类型的 bean,同时内部还有一个内部配置类 HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration,注册了 StringHttpMessageConverter 类型的 bean。注意,这两个 bean 都配置了 @ConditionalOnMissingBean,如果用户手动注册了此类型的 bean,那么自动配置类就不注册了。
首先看 HttpMessageConverters 类型的 bean,首先会获取 IOC 中所有的 HttpMessageConverter 类型 bean,按照 Bean 声明时 @Order 注解声明的顺序会总成一个 list,这个 list 作为用户额外添加的手动配置的 HttpMessageConverter 与系统默认添加的 HttpMessageConverter 一起来实例化化 HttpMessageConverters。
ObjectProvider#orderedStream方法的分析和实践请看《SpringBoot-IOC-ObjectProvider 详解.md》
HttpMessageConverters的构造函数请看《SpringBoot-HttpMessageConverters 自动配置类源码解析 -HttpMessageConvertersAutoConfiguration.md》的HttpMessageConverters小节
这个
HttpMessageConverters类型的 bean,会在WebMvcAutoConfigurationAdapter中重写configureMessageConverters的时候使用。《SpringBoot-Web 相关自动配置类源码解析 -WebMvcAutoConfiguration.md》的configureMessageConverters小节。
再看 StringHttpMessageConverter 类型的 bean,也很简单,自动配置 StringHttpMessageConverter 的主要目的修改 StringHttpMessageConverter 默认的编码格式(StandardCharsets.ISO_8859_1)为配置项 server.servlet.encoding 的配置。如果没有在配置文件中配置此配置项也没关系,因为 encoding.getCharset() 返回的,也就是 Encoding 的默认编码就是 StandardCharsets.UTF_8。这样当我们的控制器方法配置了 @ResponseBody 且返回值为 String 的时候,返回给客户端的字符串的编码就是 StandardCharsets.UTF_8,中文就不会乱码了。
其实在 SpringMVC 的时代,我们就做过类似的事情,那时为了实现这个效果,只能手动注册一个
StringHttpMessageConverter,具体请看 《SpringMVC-ContentNegotiation 内容协商.md》的简单分析RequestResponseBodyMethodProcessor小节
有关
StringHttpMessageConverter本身的源码分析,请看 《SpringMVC-ContentNegotiation 内容协商.md》的StringHttpMessageConverter小节
// 加载顺序的配置
@AutoConfiguration(after = {GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class })
// 类路径下必须存在 HttpMessageConverter ,此自动配置类才会生效,也对,HttpMessageConverter 都不存在,HttpMessageConvertersAutoConfiguration还配置个啥呢
@ConditionalOnClass(HttpMessageConverter.class)
// 只有在非 Reactive 的wen应用中才生效,目前就只有 Servlet web应用
@Conditional(NotReactiveWebApplicationCondition.class)
// 注意,这个自动配置类,还引入了 JacksonHttpMessageConvertersConfiguration、GsonHttpMessageConvertersConfiguration、JsonbHttpMessageConvertersConfiguration 这三个配置类
@Import({ JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class })
public class HttpMessageConvertersAutoConfiguration {
static final String PREFERRED_MAPPER_PROPERTY = "spring.mvc.converters.preferred-json-mapper";
// 注册 HttpMessageConverters 类型的 bean
@Bean
// 如果用户手动注册了此类型的bean,那么自动配置类就不注册了
@ConditionalOnMissingBean
public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
// 获取IOC中所有的 HttpMessageConverter 类型bean,按照Bean声明时@Order注解声明的顺序会总成一个list,
// 这个list作为用户额外添加的手动配置的HttpMessageConverter 与 系统默认添加的HttpMessageConverter一起初始化 HttpMessageConverters
// ObjectProvider#orderedStream 方法的分析和实践请看《SpringBoot-IOC-ObjectProvider详解.md》
// HttpMessageConverters的构造函数请看《SpringBoot-HttpMessageConverters自动配置类源码解析-HttpMessageConvertersAutoConfiguration.md》 的 HttpMessageConverters 小节
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
}
// StringHttpMessageConverter的自动配置类
@Configuration(proxyBeanMethods = false)
// 类路径下必须存在 StringHttpMessageConverter ,此自动配置类才会生效
@ConditionalOnClass(StringHttpMessageConverter.class)
protected static class StringHttpMessageConverterConfiguration {
// 注册 StringHttpMessageConverter 类型的 bean
@Bean
// 如果用户手动注册了此类型的bean,那么自动配置类就不注册了
@ConditionalOnMissingBean
public StringHttpMessageConverter stringHttpMessageConverter(Environment environment) {
// 自动配置 StringHttpMessageConverter 的主要目的修改StringHttpMessageConverter默认的编码格式(StandardCharsets.ISO_8859_1)为 配置项 server.servlet.encoding 的配置
// 如果没有在配置文件中配置此配置项也没关系,因为 encoding.getCharset() 返回的,也就是 Encoding 的默认编码就是 StandardCharsets.UTF_8。
// 这样当我们的控制器方法配置了 @ResponseBody 且返回值为 String的时候,返回给客户端的字符串的编码就是 StandardCharsets.UTF_8 ,中文就不会乱码了。
// 其实在SpringMVC的时代,我们就做过类似的事情,那时为了实现这个效果,只能手动注册一个 StringHttpMessageConverter,具体请看 《SpringMVC-ContentNegotiation内容协商.md》 的 简单分析RequestResponseBodyMethodProcessor 小节
// 有关 StringHttpMessageConverter 本身的源码分析,请看 《SpringMVC-ContentNegotiation内容协商.md》 的 StringHttpMessageConverter 小节
Encoding encoding = Binder.get(environment).bindOrCreate("server.servlet.encoding", Encoding.class);
StringHttpMessageConverter converter = new StringHttpMessageConverter(encoding.getCharset());
converter.setWriteAcceptCharset(false);
return converter;
}
}
// NotReactiveWebApplicationCondition
......
}
除了注册这两个 bean,HttpMessageConvertersAutoConfiguration 还引入了 JacksonHttpMessageConvertersConfiguration、GsonHttpMessageConvertersConfiguration、JsonbHttpMessageConvertersConfiguration 这三个配置类,这三个配置类中同样会注册了一些 HttpMessageConverter 类型的 bean。这些注册的 HttpMessageConverter 类型的 bean 会跟用户手动创建的 HttpMessageConverter 类型的 bean 一起作为默认添加的 HttpMessageConverter 之外的用户自定义的 HttpMessageConverter。用户自定义添加的 HttpMessageConverter 列表会跟默认添加的 HttpMessageConverter 列表进行合并,根据类型将用户自定义添加的与默认添加的类型相同或为其子类的 HttpMessageConverter 放到最终 HttpMessageConverter 列表的前面。
这里就不进行源码分析了,简单看看即可:
-
JacksonHttpMessageConvertersConfiguration:可注册MappingJackson2HttpMessageConverter,可注册MappingJackson2XmlHttpMessageConverter -
GsonHttpMessageConvertersConfiguration:可注册GsonHttpMessageConverter -
JsonbHttpMessageConvertersConfiguration:可注册JsonbHttpMessageConverter
实际上,MappingJackson2HttpMessageConverter 和 MappingJackson2XmlHttpMessageConverter、GsonHttpMessageConverter、JsonbHttpMessageConverter 在 WebMvcConfigurationSupport#addDefaultHttpMessageConverters 默认添加的 HttpMessageConverter 中也会存在,也就是说,如果条件满足,在 SpringBoot 中,这些 HttpMessageConverter 会在最终的 HttpMessageConverter 列表中存在两次。
最终的 HttpMessageConverter 列表(即 HttpMessageConverter#converters 的值)会是什么样子,我们直接采用本文中 简单调试 小节的截图。

简单总结
SpringBoot 中对 HttpMessageConverter 的管理跟 SpringMVC 框架中确实不一样。专门增加了 HttpMessageConverters 类型的 bean 来管理所有的 HttpMessageConverter,而且还专门额外创建了 HttpMessageConvertersAutoConfiguration 自动配置类来配置 HttpMessageConverters。
系统除了会默认添加 HttpMessageConverter 之外,还会添加容器中用户手动写代码注册的 HttpMessageConverter 类型的 bean,还会有自动配置类自动注册常用的 HttpMessageConverter 类型的 bean 到 IOC 容器中,辅助、减少用户自己手动写代码注册 HttpMessageConverter 类型的 bean 的工作量,非常方便。
SpringMVC 配置
HttpMessageConverter的方式请看《SpringMVC- 第十篇:基于注解配置 SpringMVC.md》的configureMessageConverters & extendMessageConverters小节