【SpringBoot】整合RabbitMQ 消费者确认模式

消费者端

目录结构

导入依赖

修改yml

业务逻辑

自动确认

手动确认


消费者端

目录结构

 

导入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
        <version>2.5.0</version>
    </dependency>
</dependencies>

修改yml

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    listener:
      simple:
        acknowledge-mode: auto

        可以看出来listener由两种类型:direct、simple。前者用于直接交换机,而后者用于其他交换机

         可以看出自动确认模式有三种方式:none、auto、manual。

        acknowledge-mode: none 表示自动确认消息(默认值)

        acknowledge-mode: manual  表示手动确认消息

        acknowledge-mode: auto 表示根据异常情况确认消息

        自动确认是指当消息一旦被消费者接收到则自动确认收到,并将消息从RabbitMQ的消息缓存中移除。但是在实际业务当中,很可能消息接收到,业务处理出现异常,那么该消息就会丢失。如果采用了手动确认方式则需要在业务处理成功后,调用channel.basicACK(),如果出现异常则调用channel.basicNack(),让其自动重新发送消息。

业务逻辑

自动确认

/**
 * 消费者自动确认消息
 * 1、yml中需要配置acknowledge-mode: none
 * 2、消费者监听实现MessageListener 
 */
@Component
public class AckListener implements MessageListener {

    @RabbitListener(queues = "test_queue_name")
    @Override
    public void onMessage(Message message) {
        System.out.println("消费者接受的消息为:" + new String(message.getBody()));
    }
}

手动确认

/**
 * 消费者手动确认消息
 * 1、yml中需要配置acknowledge-mode: manual
 * 2、消费者监听实现ChannelAwareMessageListener 
 */
@Component
public class AckListener implements ChannelAwareMessageListener {

    @RabbitListener(queues = "test_queue_name")
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        // 消息的唯一标识id
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            System.out.println("消费者接受的消息为:" + new String(message.getBody()));
            // 手动签收的第一个参数为消息的唯一标识id、第二个参数表示是否批量签收
            channel.basicAck(deliveryTag,true);
        } catch (Exception e){
            // 手动拒绝签收的第一个参数为消息id、第二个参数表示是否批量签收
            // 第三个参数消息是否重回队列
            channel.basicNack(deliveryTag,true,true);
            System.out.println("消息被拒绝签收了");
        }
    }
}

/**
 * 消费者手动确认消息
 * 1、yml中需要配置acknowledge-mode: manual
 * 2、消费者监听实现ChannelAwareMessageListener 
 */
@Component
public class AckListener implements ChannelAwareMessageListener {

    @RabbitListener(queues = "test_queue_name")
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        // 消息的唯一标识id
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            System.out.println("消费者接受的消息为:" + new String(message.getBody()));
            int i = 1 / 0;//业务逻辑故意出错进入catch块
            // 手动签收的第一个参数为消息的唯一标识id、第二个参数表示是否批量签收
            channel.basicAck(deliveryTag,true);
        } catch (Exception e){
            // 手动拒绝签收的第一个参数为消息id、第二个参数表示是否批量签收
            // 第三个参数消息是否重回队列
            channel.basicNack(deliveryTag,true,true);
            System.out.println("消息被拒绝签收了");
        }
    }
}

        注意哈:上面的终端出现了死循环是因为channel.basicNack()方法的第三个参数使其消息重回队列中重新发送,但try的业务逻辑块一直有问题,所以会重复的报错,如果第三个参数是false结果如下。

猜你喜欢

转载自blog.csdn.net/m0_65563175/article/details/130455209