【发布时间】:2017-12-22 19:22:36
【问题描述】:
我一直在为使用 AMQP 在两个微服务之间建立异步消息传递“铺平道路”。我们希望促进对每个服务使用单独的域对象,这意味着每个服务必须定义自己的跨队列传递的任何对象的副本。
我们在生产者和消费者端都使用Jackson2JsonMessageConverter,并且我们使用 Java DSL 将流与队列连接起来。
我确信有办法做到这一点,但它让我无法理解:我希望消费者端忽略从生产者传递的 __TypeID__ 标头,因为消费者可能对该事件有不同的表示(它很可能在不同的 java 包中)。
似乎已经完成了一些工作,如果使用注释@RabbitListener,则派生inferredArgumentTypeargument 并将覆盖标头信息。这正是我想做的,但我想使用 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;
}
});
}
}
我真的很想派生这个,所以开发人员不必真正处理这个问题。
有没有更简单的方法来做到这一点?
【问题讨论】:
-
抱歉,我遗漏了一些东西,但我看不出在该流定义中如何“直截了当地”推导出类型?谢谢
-
在转换器的类型映射器中使用类型 ID 映射 (
setIdClassMapping)。看我的回答。 -
我猜“直截了当”是错误的术语,如果内容类型是 application/json,我正在寻找类型的隐式处理,而不必为特定类型显式定义映射策略。这与此处讨论的想法相似:github.com/spring-cloud/spring-cloud-stream/issues/156。如果我删除了生产者端的 typeId,只留下应用程序/json,那么“开箱即用”编组会很好。
-
类型如何隐含在消息流中?通过
@RabbitListener,我们知道方法参数的类型。在使用入站负载创建通用消息时,无法推断负载的类型,因为创建消息的组件与使用消息的方法完全分离。因此,您必须使用负载类型的某种提示来配置转换器。我在答案中添加了另一个选项。 -
感谢完全有道理,感谢您的解释
标签: spring-integration spring-integration-dsl