Spring-amqp 1.6.1消费者手工对消息进行确认

前言

在使用Spring amqp创建消费者并接收消息时,通常会用到下面两个接口。

public interface MessageListener {

    void onMessage(Message message);

}

public interface ChannelAwareMessageListener {
    void onMessage(Message message, Channel channel) throws Exception;

}

我们会实现接口,并通过onMessage方法来接收消息。在接收消息后,处理业务时如果出现异常,那么消费者会不断接收到重发的消息。有时候在出现某些异常,无法处理,因此并不希望继续接收到重发,因此需要用到手工确认模式,来按需进行重发。

1.默认情况下为什么会自动重发?

在配置消费端时,通常使用下面的配置。而对于rabbit:listener-container标签并未指定“确认属性” acknowledge。默认情况下该属性为auto。

    <rabbit:listener-container 
        connection-factory="connectionFactory" >
        <rabbit:listener ref="consumer" method="listen" queue-names="myQueue" />
    </rabbit:listener-container>

当onMessage方法产生异常后,框架会调用下面的方法处理异常。

org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.rollbackOnExceptionIfNecessary(Throwable)
    public void rollbackOnExceptionIfNecessary(Throwable ex) throws Exception {

        boolean ackRequired = !this.acknowledgeMode.isAutoAck() && !this.acknowledgeMode.isManual();
        try {
            if (this.transactional) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Initiating transaction rollback on application exception: " + ex);
                }
                RabbitUtils.rollbackIfNecessary(this.channel);
            }
            if (ackRequired) {
                // We should always requeue if the container was stopping
                boolean shouldRequeue = this.defaultRequeuRejected ||
                        ex instanceof MessageRejectedWhileStoppingException;
                Throwable t = ex;
                while (shouldRequeue && t != null) {
                    if (t instanceof AmqpRejectAndDontRequeueException) {
                        shouldRequeue = false;
                    }
                    t = t.getCause();
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Rejecting messages (requeue=" + shouldRequeue + ")");
                }
                for (Long deliveryTag : this.deliveryTags) {
                    // With newer RabbitMQ brokers could use basicNack here...
                    this.channel.basicReject(deliveryTag, shouldRequeue);
                }
                if (this.transactional) {
                    // Need to commit the reject (=nack)
                    RabbitUtils.commitIfNecessary(this.channel);
                }
            }
        }
        catch (Exception e) {
            logger.error("Application exception overridden by rollback exception", ex);
            throw e;
        }
        finally {
            this.deliveryTags.clear();
        }
    }

isAutoAck方法

    public boolean isAutoAck() {
        return this == NONE;
    }

可以看到,如果acknowledge即非manul,也非none时(调用处方法名字是isAutoAck,但内部确实判断是否为NONE),那么会调用this.channel.basicReject。因此发送否定确认,最终不断收到重复发送的消息。

关于否认可以参考下面的链接。

http://www.rabbitmq.com/nack.html

2.对消息进行手工确认

为了在Spring-amqp框架中进行手工确认,在接收消息时需要实现如下的接口。

public interface ChannelAwareMessageListener {
    void onMessage(Message message, Channel channel) throws Exception;

}

此外消费者的确认模式需要配置为manual,其中确认模式包括NONE,MANUL,与AUTO三种[1]。

    <rabbit:listener-container 
        connection-factory="connectionFactory" acknowledge="manual">

那么当收到消息后,如果要否认,或确认则通过调用channel对象的下面的两个方法即可。其中basicAck进行确认,而basicNack进行否认。

        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        throw new IllegalArgumentException("Illegal");
        channel.basicAck(deliveryTag, false);
        channel.basicNack(deliveryTag, false, true);

上面代码中deliveryTag即消息消交付的一个标识,其作用域为channel。而basicNAck与basicReject都可以进行否则,二者区别参考下面的官网解释。

http://www.rabbitmq.com/nack.html

当在onMessage方法中调用basicAck确认消息后,队列中持久化的消息会被删除。而调用basicNack后,会收到rabbitmq重发的消息。若未调用basicAck确认则消息会产生堆积[2]。那么当消费者下再一次连接rabbitmq时消息会重发给消费者。

[1]Spring-amqp 配置消息的三种确认方式,http://docs.spring.io/spring-amqp/docs/1.6.5.RELEASE/reference/html/_reference.html 3.1.15 Message Listener Container Configuration
[2]消息确认 http://www.rabbitmq.com/tutorials/tutorial-two-java.html Forgotten acknowledgment

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值