我们的配置是:1 ... n带有共享数据库的消息接收器。 消息只应处理一次。
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "message-queue", durable = "true"),
exchange = @Exchange(value = TOPIC_EXCHANGE, type = "topic", durable = "true"),
key = MESSAGE_QUEUE1_RK)
)
public void receiveMessage(CustomMessage message) throws InterruptedException {
System.out.println("I have been received = " + message);
}
我们希望保证消息将被处理一次,我们有一个消息存储,其中已经处理了消息的id。 是否可以在receiveMessage之前挂钩此检查? 我们尝试使用rabbitTemplate查看MessagePostProcessor,但似乎没有用。
关于如何做到这一点的任何建议? 我们尝试使用MethodInterceptor,但这非常难看。 感谢
发现解决方案 - 感谢Gary
我创建了MessagePostProcessorInjector
来实现SmartLifecycle
在启动时,我会检查每个容器,如果是AbstractMessageListenerContainer
则添加一个客户MessagePostProccesser
和一个自定义ErrorHandler
,它查找某些类型的异常并删除它们(其他转发到defaultErrorHandler)
由于我们使用DLQ,我发现抛出异常或设置为null不会真正起作用。
我会在MPP之后发出拉取请求以忽略空消息。
答案 0 :(得分:1)
有趣; SimpleMessageListenerContainer
确实有一个属性afterReceivePostProcessors
(当前没有通过注释使用的侦听器容器工厂提供,但可以稍后注入)。
然而,这些后处理器不会提供帮助,因为我们仍然会调用监听器。
请随意打开JIRA Improvement Issue两件事:
afterReceivePostProcessors
(更正,该物业确实由工厂暴露)。
修改强>
工作原理......
在上下文初始化期间......
RabbitListenerEndpointRegistry
start()
,并启动为autoStartup
配置的所有容器(默认)。要在容器启动之前进行进一步配置(例如,对于容器工厂当前未公开的属性),请将autoStartup
设置为false
。
然后,您可以从注册表中获取容器(作为集合或id
)。只需@Autowire
您应用中的注册表。
如果使用Spring AMQP 2.0或更高版本并且您正在使用其工厂,则将容器转换为SimpleMessageListenerContainer
(或者DirectMessageListenerContainer
。
设置其他属性(例如afterReceiveMessagePostProcessors
);然后start()
容器。
注意:在我们增强容器以允许返回null
的MPP之前,可能的替代方法是从MPP中抛出AmqpRejectAndDontRequeueException
。但是,如果您配置了DLQ,这可能不是您想要的。
答案 1 :(得分:0)
当消息重复时,从DuplicateChecking MPP的postProcessMessage()抛出从ImmediateAcknowledgeAmqpException延伸的异常也不会将消息传递给Rabbit Listener。