Почему AmqpChannelFactoryBean с Jackson2JsonMessageConverter не сохраняет тип?

Я пытаюсь использовать интеграцию Spring с RabbitMQ, используя каналы интеграции Spring, поддерживаемые RabbitMQ. (Что кажется почти не задокументированным по какой-то причине, это что-то новое?).

Для этого, кажется, я могу использовать AmqpChannelFactoryBean для создания канала. Чтобы настроить преобразование сообщений, я использую файл Jackson2JsonMessageConverter.

Когда я использую GenericMessage с полезной нагрузкой POJO, он отказывается десериализовать его из Java, в основном потому, что не знает тип. Я ожидал, что тип будет автоматически помещен в заголовок, но в заголовке есть только __TypeId__=org.springframework.messaging.support.GenericMessage.

В Spring boot мой класс конфигурации выглядит так:

@Configuration
public class IntegrationConfiguration {

    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    public AmqpChannelFactoryBean myActivateOutChannel(CachingConnectionFactory connectionFactory,
        MessageConverter messageConverter) {

        AmqpChannelFactoryBean factoryBean = new AmqpChannelFactoryBean(true);
        factoryBean.setConnectionFactory(connectionFactory);
        factoryBean.setQueueName("myActivateOut");
        factoryBean.setPubSub(false);
        factoryBean.setAcknowledgeMode(AcknowledgeMode.AUTO);
        factoryBean.setDefaultDeliveryMode(MessageDeliveryMode.PERSISTENT);
        factoryBean.setMessageConverter(messageConverter);
        return factoryBean;
    }

    @Bean
    @ServiceActivator(inputChannel = "bsnkActivateOutChannel", autoStartup="true")
    public MessageHandler mqttOutbound() {

        return m -> System.out.println(m);
    }

}

Отправка осуществляется так:

private final MessageChannel myActivateOutChannel;

@Autowired
public MySender(MessageChannel myActivateOutChannel) {
    this.myActivateOutChannel = myActivateOutChannel;
}

@Override
public void run(ApplicationArguments args) throws Exception {
    MyPojo pojo = new MyPojo();
    Message<MyPojo> msg = new GenericMessage<>(pojo);

    myActivateOutChannel.send(msg);
}

Если я установлю свой собственный classmapper, все будет работать так, как должно. Но мне пришлось бы использовать много MessageConverters, если бы я настраивал такие вещи. Например.

    converter.setClassMapper(new ClassMapper() {

        @Override
        public void fromClass(Class< ? > clazz, MessageProperties properties) {
        }

        @Override
        public Class< ? > toClass(MessageProperties properties) {
            return MyPojo.class;
        }

    });

Я использую это неправильно? Я пропустил какую-то конфигурацию? Любые другие предложения?

Спасибо!! :)

Примечание. Глядя на вещи подробнее, я предполагаю, что способ «интеграции Spring» будет состоять в том, чтобы добавить преобразователь JSON интеграции Spring с каждой стороны, что означает также добавление двух дополнительных прямых каналов на очередь RabbitMQ? Мне это кажется неправильным, так как тогда у меня тройное количество каналов (6! для входа/выхода), но, может быть, именно так должна использоваться структура? Соедините все простые шаги с прямыми каналами? (Сохраню ли я постоянство, которое предлагают каналы RabbitMQ в этом случае? Или мне нужен какой-то механизм транзакций, если я этого хочу? Или это присуще тому, как работают прямые каналы?)

Я также заметил, что теперь есть как Spring-integration MessageConverter, так и Spring-amqp MessageConverter. Последний - тот, который я использовал. Будет ли другой работать так, как я хочу? Беглый взгляд на код показывает, что он не сохраняет тип объекта в заголовке сообщения?


person bluemind    schedule 10.10.2017    source источник


Ответы (1)


До версии 4.3 каналы с поддержкой amqp поддерживали только сериализуемые полезные нагрузки; обходной путь заключался в том, чтобы вместо этого использовать адаптеры каналов (которые поддерживают сопоставление).

INT-3975 представил новое свойство extractPayload, которое заставляет заголовки сообщений сопоставляться с rabbitmq заголовки, а тело сообщения — это просто полезная нагрузка, а не сериализованный GenericMessage.

Установка extractPayload в true должна решить вашу проблему.

person Gary Russell    schedule 10.10.2017
comment
Ваше здоровье! Завтра попробую :) - person bluemind; 10.10.2017
comment
Да, это работает отлично! Я приму этот ответ :) Есть ли какое-нибудь очевидное место в каком-либо из руководств, где я мог бы найти это? Не жаловаться! Но это была бы часть для меня слишком досконально прочитана :) - person bluemind; 11.10.2017
comment
Круто, это то, что я хотел :) Полностью пропустил абзац, я думаю, потому что во введении есть ссылки на шлюзы и адаптеры, но не на поддерживаемые каналы сообщений :) Ура! - person bluemind; 11.10.2017