首页 > 解决方案 > RestTemplateBuilder中重复的MessageConverters?

问题描述

我正在spring-boot使用spring-webjackson

问题:当RestTemplatespring 自动初始化 a 时,构造函数会收到一些重复的MessageConverters

org.springframework.http.converter.ByteArrayHttpMessageConverter@6a1b4854,
org.springframework.http.converter.StringHttpMessageConverter@2d5b549b, 
org.springframework.http.converter.StringHttpMessageConverter@6a175162, 
org.springframework.http.converter.ResourceHttpMessageConverter@7641c4e7, 
org.springframework.http.converter.ResourceRegionHttpMessageConverter@650a0b50, 
org.springframework.http.converter.xml.SourceHttpMessageConverter@55e3b64d, 
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@52f71d2, 
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@f3c27e9, 
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@7d31fb6c, 
org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter@701c413, 
org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter@48543f11

你看,有3个重复:

StringHttpMessageConverter
MappingJackson2HttpMessageConverter
MappingJackson2XmlHttpMessageConverter

由于我自己没有初始化任何消息转换器:为什么应用程序上下文根本包含重复的转换器,然后将其添加到 resttemplate?

特别是:如果某些转换器出现重复(但配置不同),这不会混淆(反)序列化吗?

例如:ObjectMapper第一个MappingJackson2HttpMessageConverter包含registeredModuleTypes [Jdk8Module, JavaTimeModule, ParamterNamesModule, JsonComponentModule, GeoModule]多于第二个(仅包含:)[Jdk8Module, JavaTimeModule]

那有意义吗?

它是通过实例化的RestTemplateAutoConfiguration.restTemplateBuilder(),所有重复项MessageConverters都已经存在。

标签: javaspringspring-bootjacksonspring-web

解决方案


罪魁祸首在这里HttpMessageConverters

public HttpMessageConverters(boolean addDefaultConverters,
        Collection<HttpMessageConverter<?>> converters) {
    List<HttpMessageConverter<?>> combined = getCombinedConverters(converters,
            addDefaultConverters ? getDefaultConverters() : Collections.emptyList());
    combined = postProcessConverters(combined);
    this.converters = Collections.unmodifiableList(combined);
}

具体来说,这一行(格式化)

List<HttpMessageConverter<?>> combined = 
       getCombinedConverters(
           converters, 
           addDefaultConverters 
               ? getDefaultConverters() 
               : Collections.emptyList());

converters集合包含扫描HttpMessageConverter的(S)。
基于环境。

在此处输入图像描述

然后将该列表与由提供的默认列表连接WebMvcConfigurationSupport

在此处输入图像描述

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    private static final boolean romePresent;
    private static final boolean jaxb2Present;
    private static final boolean jackson2Present;
    private static final boolean jackson2XmlPresent;
    private static final boolean jackson2SmilePresent;
    private static final boolean jackson2CborPresent;
    private static final boolean gsonPresent;
    private static final boolean jsonbPresent;
    ...

InfactWebMvcConfigurationSupport州的文件

这个类注册……一系列HttpMessageConverters取决于类路径上可用的第三方库。

扫描HttpMessageConverter的(s)通过 找到并实例化HttpMessageConvertersAutoConfiguration,其文档是

自动配置HttpMessageConverters.

该类本身暴露了一个StringHttpMessageConverter

@Bean
@ConditionalOnMissingBean
public StringHttpMessageConverter stringHttpMessageConverter() {
    StringHttpMessageConverter converter = new StringHttpMessageConverter(
            this.properties.getCharset());
    converter.setWriteAcceptCharset(false);
    return converter;
}

比,它导入 Jackson 或 Gson 自动配置

@Import({ 
    JacksonHttpMessageConvertersConfiguration.class
    GsonHttpMessageConvertersConfiguration.class,
    JsonbHttpMessageConvertersConfiguration.class 
})

这就是那些基于环境的“总和”到预定义的。


Spring 不会被重复项弄糊涂,因为它只接受第一个兼容的。
看看如何HttpMessageConverter选择an

在此处输入图像描述

你可以看到它只是一个简单的 for 循环,每个转换都被要求说“我可以这样做吗?” 通过canWrite方法

在此处输入图像描述

选择第一个有效值。


推荐阅读