我正在使用spring-boot
与spring-web
和jackson
。
问题:当弹簧自动初始化RestTemplate
时,构造函数会收到一些重复的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
已经存在。
罪魁祸首就在这里,在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;
}
比,它进口杰克逊或Gson自动配置
@Import({
JacksonHttpMessageConvertersConfiguration.class
GsonHttpMessageConvertersConfiguration.class,
JsonbHttpMessageConvertersConfiguration.class
})
这就是那些基于环境的那些被“加总”到预定义的那些。
Spring不会被重复项混淆,因为它只需要第一个兼容的东西。
看看如何选择HttpMessageConverter
你可以看到它只是一个简单的for循环,每个转换都被要求说“我可以这样做吗?”通过canWrite
方法
选择第一个有效期。