Повторяющиеся MessageConverters в RestTemplateBuilder? - PullRequest
0 голосов
/ 04 апреля 2019

Я использую 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

Поскольку я сам не инициализирую конвертеры сообщений: почему контекст приложения вообще содержит дубликаты конвертеров, которые затем добавляются вшаблон перезапуска?

Особенно: не смущает ли это (де) сериализацию, если некоторые конвертеры дублируются (но с другой конфигурацией)?

Например: ObjectMapper первого MappingJackson2HttpMessageConverter содержит больше registeredModuleTypes [Jdk8Module, JavaTimeModule, ParamterNamesModule, JsonComponentModule, GeoModule], чем 2-й (который содержит только: [Jdk8Module, JavaTimeModule]).

Имеет ли это смысл?

Он создается через RestTemplateAutoConfiguration.restTemplateBuilder(), там вседубликат MessageConverters уже присутствует.

1 Ответ

1 голос
/ 04 апреля 2019

Виновник здесь, на 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).
В зависимости от среды.

enter image description here

Этот список затем объединяется с по умолчанию , предоставленным WebMvcConfigurationSupport

enter image description here

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;
    ...

Infact документация для WebMvcConfigurationSupport состояний

Этот класс регистрируется ... ... диапазон HttpMessageConverters в зависимости от сторонних библиотек, доступных на пути к классам.

Сканированные HttpMessageConverter найдены и созданы с помощью HttpMessageConvertersAutoConfiguration, документация которых

Автоконфигурация для HttpMessageConverters.

Этот класс представляет собой StringHttpMessageConverter

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

Чем импортируются автоконфигурации Джексона или Гсона

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

И вот как эти основанные на окружающей среде "суммируются" с предопределенными.


Spring не смущает дубликаты, потому что он просто берет первое, которое совместимо.
Посмотрите, как выбирается HttpMessageConverter

enter image description here

Вы можете видеть, что это просто цикл for, и каждого конверта просят сказать "я могу это сделать?" по методу canWrite

enter image description here

Первый действительный выбран.

...