如何创建@RabbitListener是幂等的

时间:2017-09-20 06:28:02

标签: java rabbitmq amqp spring-amqp

我们的配置是: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之后发出拉取请求以忽略空消息。

2 个答案:

答案 0 :(得分:1)

有趣; SimpleMessageListenerContainer确实有一个属性afterReceivePostProcessors当前没有通过注释使用的侦听器容器工厂提供,但可以稍后注入)。

然而,这些后处理器不会提供帮助,因为我们仍然会调用监听器。

请随意打开JIRA Improvement Issue两件事:

  1. 公开侦听器容器工厂中的afterReceivePostProcessors
  2. 如果后处理器返回null,则跳过调用侦听器方法。
  3. (更正,该物业确实由工厂暴露)。

    修改

    工作原理......

    在上下文初始化期间......

    1. 对于bean后处理器检测到的每个注释,将在RabbitListenerEndpointRegistry
    2. 中创建并注册容器
    3. 在上下文初始化结束时,注册表为start(),并启动为autoStartup配置的所有容器(默认)。
    4. 要在容器启动之前进行进一步配置(例如,对于容器工厂当前未公开的属性),请将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。