Интеграция Spring - предполагаемые типы AMQP в Java DSL?

Я работал над «асфальтированной дорогой» для настройки асинхронного обмена сообщениями между двумя микросервисами с использованием AMQP. Мы хотим продвигать использование отдельных объектов домена для каждой службы, а это означает, что каждая служба должна определять свою собственную копию любых объектов, передаваемых через очередь.

Мы используем Jackson2JsonMessageConverter как на стороне производителя, так и на стороне потребителя, и мы используем Java DSL для передачи потоков в/из очередей.

Я уверен, что есть способ сделать это, но он ускользает от меня: я хочу, чтобы сторона потребителя игнорировала заголовок __TypeID__, который передается от производителя, поскольку потребитель может иметь другое представление этого события (и, скорее всего, находиться в другом пакете Java).

Похоже, что была проделана такая работа, что при использовании аннотации @RabbitListener выводится аргумент inferredArgumentType, который переопределяет информацию заголовка. Это именно то, что я хотел бы сделать, но я хотел бы использовать для этого Java DSL. Я еще не нашел чистого способа сделать это, и, возможно, я просто упускаю что-то очевидное. Кажется, было бы довольно просто вывести тип при использовании следующего DSL:

return IntegrationFlows
        .from(
                Amqp.inboundAdapter(factory, queueRemoteTaskStatus())
                        .concurrentConsumers(10)
                        .errorHandler(errorHandler)
                        .messageConverter(messageConverter)
        )
        .channel(channelRemoteTaskStatusIn())
        .handle(listener, "handleRemoteTaskStatus")
        .get();

Однако это приводит к исключению ClassNotFound. Единственный способ, который я нашел, чтобы обойти это, — это установить собственный преобразователь сообщений, который требует явного определения типа.

public class ForcedTypeJsonMessageConverter extends Jackson2JsonMessageConverter {

    ForcedTypeJsonMessageConverter(final Class<?> forcedType) {
        setClassMapper(new ClassMapper() {

            @Override
            public void fromClass(Class<?> clazz, MessageProperties properties) {
                    //this class is only used for inbound marshalling.
            }

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

Я бы очень хотел, чтобы это было выведено, поэтому разработчику не нужно особо с этим сталкиваться.

Есть ли более простой способ сделать это?


person Tyler Van Gorder    schedule 22.12.2017    source источник
comment
Извините, я что-то упустил, но я не понимаю, как в этом определении потока так просто получить тип? Спасибо   -  person Artem Bilan    schedule 22.12.2017
comment
Используйте сопоставление идентификатора типа (setIdClassMapping) в преобразователе типов преобразователя. Смотрите мой ответ.   -  person Gary Russell    schedule 22.12.2017
comment
Я предполагаю, что прямой путь - неправильный термин, я ищу неявную обработку типов, если тип содержимого - это приложение/json, без необходимости явно определять стратегию сопоставления для определенных типов. Эта идея аналогична той, что обсуждалась здесь: github.com/spring -cloud/spring-cloud-stream/issues/156. Если я удалю typeId на стороне производителя и просто оставлю application/json, было бы неплохо выйти из стандартного маршалинга.   -  person Tyler Van Gorder    schedule 23.12.2017
comment
Как тип может быть неявным в потоке сообщений? С помощью @RabbitListener мы знаем тип параметра метода. При создании общего сообщения с входящей полезной нагрузкой невозможно определить тип полезной нагрузки, поскольку компонент, создающий сообщение, полностью отделен от метода, потребляющего сообщение. Следовательно, вы должны настроить преобразователь с какой-либо подсказкой для типа полезной нагрузки. Я добавил еще один вариант в свой ответ.   -  person Gary Russell    schedule 23.12.2017
comment
Спасибо имеет смысл, спасибо за объяснение   -  person Tyler Van Gorder    schedule 23.12.2017


Ответы (1)


Самый простой способ — сконфигурировать DefaultJackson2JavaTypeMapper преобразователя Джексона с TypeIdMapping (setIdClassMapping()).

В системе-отправителе сопоставьте карту foo:com.one.Foo и карту системы-получателя foo:com.two.Foo.

Затем заголовок __TypeId__ получает foo, и принимающая система сопоставляет его со своим представлением Foo.

ИЗМЕНИТЬ

Другой вариант — добавить afterReceiveMessagePostProcessor в контейнер прослушивателя адаптера входящего канала — это может изменить заголовок __TypeId__.

person Gary Russell    schedule 22.12.2017