springboot中RabbitMQ死信队列的实现示例

 更新时间:2024年01月23日 10:06:30   作者:Java小生不才  
死信队列是一种特殊的消息队列,用来存储无法被正常消费的消息,常被用来实现延迟处理,异常消息处理等,本文主要介绍了springboot中RabbitMQ死信队列的实现示例,感兴趣的可以了解一下

1. 死信队列

死信队列是一种特殊的消息队列,用来存储无法被正常消费的消息,常被用来实现延迟处理,异常消息处理等,提高了系统的可伸缩性和容错性,能够应对高并发和异常消息。
死信队列中的消息被称为死信消息,用来分发死信消息的交换机被称为死信交换机(Dead Letter Exchange,DLX)
死信队列在实际项目中的应用场景有很多如:

  • 订单超时未支付,将此消息放入死信队列中,等待后续处理(延迟等待)
  • 消息消费失败将消息放入死信队列中进行重试(消息重试机制)

在这里插入图片描述

2.正常消息成为死信消息的条件

  • 消息到了过期时间仍然未被消费者消费
  • 队列已满无法保存新消息
  • 消息被拒绝消费且未设置重新放入队列

在这里插入图片描述

3.消费者1

package com.hong.rabbitmq9;

import com.hong.utils.RabbitMQUtil;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 死信队列消费者1
 * @Author: hong
 * @Date: 2024-01-17 21:04
 * @Version: 1.0
 **/
public class Consumer1 {
    //正常交换机名称
    public static final String NORMAL_EXCHANGE = "normal_exchange";
    //死信交换机名称
    public static final String DEAD_EXCHANGE = "dead_exchange";
    //正常队列名称
    public static final String NORMAL_QUEUE = "normal_queue";
    //死信队列名称
    public static final String DEAD_QUEUE = "dead_queue";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtil.getChannel();
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

        channel.queueDeclare(DEAD_QUEUE,false,false,false,null);
        channel.queueBind(DEAD_QUEUE,DEAD_EXCHANGE,"lisi");

        //正常队列绑定死信队列信息
        Map<String,Object> map = new HashMap<>();
        map.put("x-dead-letter-exchange",DEAD_EXCHANGE);
        map.put("x-dead-letter-routing-key", "lisi");
        //声明正常队列
        channel.queueDeclare(NORMAL_QUEUE,false,false,false,map);
        channel.queueBind(NORMAL_QUEUE,NORMAL_EXCHANGE,"zhangsan");

        System.out.println("Consumer1等待接收消息:");
        DeliverCallback deliverCallback = (comsumerTag, message) -> {
            System.out.println( "routingKey:" + message.getEnvelope().getRoutingKey() + ",消息:" + new String(message.getBody(), StandardCharsets.UTF_8));
        };

        CancelCallback cancelCallback = var -> {
        };

        channel.basicConsume(NORMAL_QUEUE,true,deliverCallback,cancelCallback);

    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.生产者

package com.hong.rabbitmq9;

import com.hong.utils.RabbitMQUtil;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;

/**
 * @Description: 死信队列消息生产者
 * @Author: hong
 * @Date: 2024-01-17 20:49
 * @Version: 1.0
 **/
public class Producer {
    public static final String NORMAL_EXCHANGE = "normal_exchange";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtil.getChannel();

        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

        //设置消息的 TTL 时间 10s
        AMQP.BasicProperties properties = new AMQP.BasicProperties()
                .builder().expiration("10000").build();

        //该信息是用作演示队列个数限制
        for (int i = 1; i < 11; i++) {
            String message = "info" + i;
            channel.basicPublish(NORMAL_EXCHANGE, "zhangsan", properties, message.getBytes());
            System.out.println("生产者发送消息:" + message);
        }
    }

}

启动消费者1后马上关闭消费者1,模拟消费者1接收不到消息,再启动生产者

在这里插入图片描述

在这里插入图片描述

生产者发送10条正常队列中有10条消息

在这里插入图片描述

10s后正常队列中的消息由于没有消费者消费进入死信队列中

在这里插入图片描述

5.消费者2

package com.hong.rabbitmq9;

import com.hong.utils.RabbitMQUtil;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 死信队列-死信消费者
 * @Author: hong
 * @Date: 2024-01-17 21:31
 * @Version: 1.0
 **/
public class Consumer2 {
    public static final String DEAD_EXCHANGE = "dead_exchange";
    public static final String DEAD_QUEUE = "dead_queue";
    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtil.getChannel();

        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

        channel.queueDeclare(DEAD_QUEUE,false,false,false,null);
        channel.queueBind(DEAD_QUEUE,DEAD_EXCHANGE,"lisi");


        System.out.println("Consumer2等待接收死信消息:");
        DeliverCallback deliverCallback = (comsumerTag, message) -> {
            System.out.println( "routingKey:" + message.getEnvelope().getRoutingKey() + ",消息:" + new String(message.getBody(), StandardCharsets.UTF_8));
        };

        CancelCallback cancelCallback = var -> {
        };

        channel.basicConsume(DEAD_QUEUE,true,deliverCallback,cancelCallback);
    }
}

启动消费者2,使其消费死信队列中的消息

在这里插入图片描述

6.队列达到最大长度

以上代码是TTL,队列达到最大长度只要将上述代码稍微改动一下即可

6.1.注释掉生产者代码中的ttl部分

package com.hong.rabbitmq9;

import com.hong.utils.RabbitMQUtil;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;

/**
 * @Description: 死信队列消息生产者
 * @Author: hong
 * @Date: 2024-01-17 20:49
 * @Version: 1.0
 **/
public class Producer {
    public static final String NORMAL_EXCHANGE = "normal_exchange";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtil.getChannel();

        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);

        //设置消息的 TTL 时间 10s
//        AMQP.BasicProperties properties = new AMQP.BasicProperties()
//                .builder().expiration("10000").build();

        //该信息是用作演示队列个数限制
        for (int i = 1; i < 11; i++) {
            String message = "info" + i;
            channel.basicPublish(NORMAL_EXCHANGE, "zhangsan", null, message.getBytes());
            System.out.println("生产者发送消息:" + message);
        }
    }
}

6.2.消费者1代码中加最大长度

package com.hong.rabbitmq9;

import com.hong.utils.RabbitMQUtil;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 死信队列消费者1
 * @Author: hong
 * @Date: 2024-01-17 21:04
 * @Version: 1.0
 **/
public class Consumer1 {
    //正常交换机名称
    public static final String NORMAL_EXCHANGE = "normal_exchange";
    //死信交换机名称
    public static final String DEAD_EXCHANGE = "dead_exchange";
    //正常队列名称
    public static final String NORMAL_QUEUE = "normal_queue";
    //死信队列名称
    public static final String DEAD_QUEUE = "dead_queue";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMQUtil.getChannel();
        channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
        channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);

        channel.queueDeclare(DEAD_QUEUE,false,false,false,null);
        channel.queueBind(DEAD_QUEUE,DEAD_EXCHANGE,"lisi");

        //正常队列绑定死信队列信息
        Map<String,Object> map = new HashMap<>();
        map.put("x-dead-letter-exchange",DEAD_EXCHANGE);
        map.put("x-dead-letter-routing-key", "lisi");
        map.put("x-max-length",8);
        //声明正常队列
        channel.queueDeclare(NORMAL_QUEUE,false,false,false,map);
        channel.queueBind(NORMAL_QUEUE,NORMAL_EXCHANGE,"zhangsan");

        System.out.println("Consumer1等待接收消息:");
        DeliverCallback deliverCallback = (comsumerTag, message) -> {
            System.out.println( "routingKey:" + message.getEnvelope().getRoutingKey() + ",消息:" + new String(message.getBody(), StandardCharsets.UTF_8));
        };

        CancelCallback cancelCallback = var -> {
        };

        channel.basicConsume(NORMAL_QUEUE,true,deliverCallback,cancelCallback);

    }
}

启动消费者1后立马关闭,模拟队列已满

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

到此这篇关于springboot中RabbitMQ死信队列的实现示例的文章就介绍到这了,更多相关springboot RabbitMQ死信队列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • 深度源码解析Java 线程池的实现原理

    深度源码解析Java 线程池的实现原理

    如何高效的使用这些资源就是程序员在平时写代码时候的一个努力的方向。本文要说的线程池就是一种对 CPU 利用的优化手段。对Java 线程池的实现原理相关知识感兴趣的朋友一起看看吧
    2021-05-05
  • Java 三种进制的数值常量操作

    Java 三种进制的数值常量操作

    这篇文章主要介绍了Java 三种进制的数值常量操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • 详解高性能缓存Caffeine原理及实战

    详解高性能缓存Caffeine原理及实战

    Caffeine是基于Java 8开发的,提供了近乎最佳命中率的高性能本地缓存组件,Spring5开始不再支持Guava Cache,改为使用Caffeine。Caffeine提供的内存缓存使用参考Google guava的API
    2021-06-06
  • Java原生序列化和反序列化代码实例

    Java原生序列化和反序列化代码实例

    这篇文章主要介绍了Java原生序列化和反序列化代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • springboot项目idea热部署的教程详解

    springboot项目idea热部署的教程详解

    这篇文章主要介绍了springboot项目idea热部署,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • velocity显示List与Map的方法详细解析

    velocity显示List与Map的方法详细解析

    以下是对velocity显示List与Map的方法进行了详细的介绍。需要的朋友可以过来参考下
    2013-08-08
  • java显示当前的系统时间

    java显示当前的系统时间

    这篇文章主要介绍了java如何显示当前的系统时间,代码很简单,自己可以自定义显示的系统时间的颜色和字体,需要的朋友可以参考下
    2015-10-10
  • java.lang.UnsatisfiedLinkError: %1 不是有效的Win32应用程序错误解决

    java.lang.UnsatisfiedLinkError: %1 不是有效的Win32应用程序错误解决

    这篇文章主要给大家介绍了关于java.lang.UnsatisfiedLinkError: %1 不是有效的Win32应用程序错误的解决方法,文中介绍的非常详细,需要的朋友们可以参考学习,下面来一起看看吧。
    2017-03-03
  • Java使用JMeter进行高并发测试

    Java使用JMeter进行高并发测试

    软件的压力测试是一种保证软件质量的行为,本文主要介绍了Java使用JMeter进行高并发测试,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Java中compareTo方法使用小结

    Java中compareTo方法使用小结

    compareTo是Java中Object类中的一个方法,它的作用是比较两个对象的大小关系,本文主要介绍了Java中compareTo方法使用小结,感兴趣的可以了解一下
    2024-01-01

最新评论