RestTemplateBuilder中重复的MessageConverters?
Posted
技术标签:
【中文标题】RestTemplateBuilder中重复的MessageConverters?【英文标题】:Duplicate MessageConverters in RestTemplateBuilder? 【发布时间】:2019-08-26 07:35:33 【问题描述】:我将spring-boot
与spring-web
和jackson
一起使用。
问题:当一个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?
特别是:如果某些转换器出现重复(但配置不同),这不会混淆(反)序列化吗?
例如:第一个MappingJackson2HttpMessageConverter
的ObjectMapper
包含的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?的主要内容,如果未能解决你的问题,请参考以下文章