RestTemplateBuilder中重复的MessageConverters?

Posted

技术标签:

【中文标题】RestTemplateBuilder中重复的MessageConverters?【英文标题】:Duplicate MessageConverters in RestTemplateBuilder? 【发布时间】:2019-08-26 07:35:33 【问题描述】:

我将spring-bootspring-webjackson 一起使用。

问题:当一个RestTemplate被spring自动初始化时,构造函数接收到一些重复的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?

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

例如:第一个MappingJackson2HttpMessageConverterObjectMapper 包含的registeredModuleTypes [Jdk8Module, JavaTimeModule, ParamterNamesModule, JsonComponentModule, GeoModule] 比第二个(仅包含:[Jdk8Module, JavaTimeModule])更多。

这有意义吗?

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

【问题讨论】:

你能在构造函数处设置一个断点并发布整个调用堆栈吗?我想看看它是从哪里实例化的。 来自RestTemplateAutoConfiguration.restTemplateBuilder()。所以它只是注入任何在类路径中找到的HttpMessageConverters。问题是为什么会有重复? 嗯,这就是我所能得到的。 添加了关于 Spring 如何选择 HttpMessageConverter 的说明。见底部。 【参考方案1】:

罪魁祸首在这里,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;
    ...

编写WebMvcConfigurationSupport 状态的文档

这个类注册... ... 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

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

选择第一个有效的。

【讨论】:

tyvm 供您详细了解! @membersound 哦,没问题。好玩。如果您需要其他说明,请告诉我。

以上是关于RestTemplateBuilder中重复的MessageConverters?的主要内容,如果未能解决你的问题,请参考以下文章

通过@Bean 提供的 RestTemplateBuilder 流式上传缓冲完整文件

resttemplatebuilder 在哪个jar包

将数组转换为 JSON [重复]

选择没有任何类的元素[重复]

J2me 的 FFT 示例

子进程 cp 返回错误 - bufsize 必须是整数 [重复]