RestTemplateBuilder 中的重复 MessageConverters?

Duplicate MessageConverters in RestTemplateBuilder?

我将 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 比第二个(仅包含:[Jdk8Module, JavaTimeModule])包含更多 registeredModuleTypes [Jdk8Module, JavaTimeModule, ParamterNamesModule, JsonComponentModule, GeoModule]

这有意义吗?

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

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

的文档

This class registers ... ... a range of HttpMessageConverters depending on the third-party libraries available on the classpath.

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

Auto-configuration for HttpMessageConverters.

那个 class 自己暴露了一个 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 
})

这就是那些基于环境的 "summed" 与预定义的


Spring 不会被重复混淆,因为它只取第一个兼容的。
看看如何选择 HttpMessageConverter

你可以看到它只是一个简单的for循环,并且要求每个convert通过canWrite方法说"can I do this?"

第一个有效的被选中。