RabbitMQ(二)、死信队列(Dead Letter)

什么是死信交换机和死信队列

死信交换机:"死信"的消息经由一个交换机到达另一个队列,这样用于处理”死信“的交换机就是死信交换机(dead-letter-exchange,DLX)

死信队列:与死信交换机绑定的队列就是死信队列。“死信”消息会被RabbitMQ进行特殊处理,如果配置了死信队列信息,那么该消息将会被丢进死信队列中,如果没有配置,则该消息将会被丢弃。

消息什么时候变成死信

“死信”是RabbitMQ中的一种消息机制,当你在消费消息时,如果队列里的消息出现以下三种情况,那么该消息将成为“死信”。

  • 消息在队列的存活时间超过设置的TTL时间(如果队列和消息都是设置了TTL,将以最小的为主)
  • 消息被否定确认,使用 channel.basicNackchannel.basicReject ,并且此时 requeue 属性被设置为 false
  • 消息队列的消息数量已经超过最大队列长度/最大大小限制;

死信处理过程

  • DLX 也是一个正常的 Exchange,和一般的 Exchange 没有区别,它能在任何的队列上被指定,实际上就是设置某个队列的属性(x-dead-letter-exchange)。

  • 当这个队列中有死信时,RabbitMQ 就会自动的将这个消息重新发布到设置的 dead-letter-exchange 上去,进而被路由到死信队列。

  • 死信队列对应的消费端可以监听这个队列中的消息做相应的处理。

死信队列如何使用

1. 引入依赖

<dependency>
	<groupId>com.rabbitmq</groupId>
	<artifactId>amqp-client</artifactId>
	<version>5.7.3</version>
</dependency>

2. 创建配置类

public class RabbitMQConfig {
    private RabbitMQConfig() {
    }

    // 主机IP
    public static final String HOST = "127.0.0.1";
    // 主机port
    public static final Integer PORT = 5672;
    // 主机port
    public static final String VHOST = "/";
    // 主机port
    public static final String USERNAME = "admin";
    // 主机port
    public static final String PASSWORD = "admin";
    // 交换机名称
    public static final String DIRECT_EXCHANGE = "direct_exchange";
    // 队列名称
    public static final String QUEUE_NAME = "direct_queue";
    // Routing key
    public static final String ROUTING_KEY = "kiss";

    // 死信交换机名称
    public static final String DEAD_LETTER_EXCHANGE = "DLX_exchange";
    // 死信队列名称
    public static final String DEAD_LETTER_QUEUE = "DLX_queue";
    // 死信交换机和死信队列 Routing key, # 代表所有消息
    public static final String DEAD_LETTER_ROUTING_KEY = "#";
}

3. 消费端代码

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

/**
 * 消费者
 */
public class MessageConsumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        // 设置主机IP
        factory.setHost(RabbitMQConfig.HOST);
        // 设置端口
        factory.setPort(RabbitMQConfig.PORT);
        // 设置 Vhost
        factory.setVirtualHost(RabbitMQConfig.VHOST);

        // 设置访问用户
        factory.setUsername(RabbitMQConfig.USERNAME);
        factory.setPassword(RabbitMQConfig.PASSWORD);
        // 建立连接
        Connection connection = factory.newConnection();
        // 创建Channel消息通道
        Channel channel = connection.createChannel();

        /**
         * 声明交换机,参数String exchange, String type, boolean durable, boolean autoDelete, Map<String, Object> arguments
         *
         * String exchange:指定交换机名称
         * String type:路由类型,direct、topic、fanout
         * boolean durable:是否持久化
         * boolean autoDelete:是否自动删除
         * Map<String, Object> arguments:其他参数
         */
        channel.exchangeDeclare(RabbitMQConfig.DIRECT_EXCHANGE, "direct", false, false, null);

        // 设置队列参数:x-dead-letter-exchange为指定当前队列的死信交换机
        Map<String, Object> arguments = new HashMap<>();
        arguments.put("x-dead-letter-exchange", RabbitMQConfig.DEAD_LETTER_EXCHANGE);
        /**
         * 声明队列,参数String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
         * String queue:指定队列名称
         * boolean durable:是否持久化
         * boolean exclusive:是否排他,既是否创建者私有,如果为true,会对当前队列加锁,其他通道不能访问,并且
         * 					 在连接关闭时会自动删除,不受持久化和自动删除限制
         * boolean autoDelete:是否自动删除
         * Map<String, Object> arguments:其他参数
         */
        channel.queueDeclare(RabbitMQConfig.QUEUE_NAME, false, false, false, arguments);

        /**
         * 绑定交换和队列,参数String queue, String exchange, String routingKey, Map<String, Object> arguments
         */
        channel.queueBind(RabbitMQConfig.QUEUE_NAME, RabbitMQConfig.DIRECT_EXCHANGE, RabbitMQConfig.ROUTING_KEY, null);

        /*********************声明死信交换机和死信队列,并绑定*************************/
        channel.exchangeDeclare(RabbitMQConfig.DEAD_LETTER_EXCHANGE, "topic", false, false, null);
        channel.queueDeclare(RabbitMQConfig.DEAD_LETTER_QUEUE, false, false, false, null);
        channel.queueBind(RabbitMQConfig.DEAD_LETTER_QUEUE, RabbitMQConfig.DEAD_LETTER_EXCHANGE,
                RabbitMQConfig.DEAD_LETTER_ROUTING_KEY);

        // 创建消费者
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                // 获取消息
                String msg = new String(body, "UTF-8");
                System.out.println("consumer message:" + msg);
            }
        };

        // 开始获取消息String queue, boolean autoAck, Consumer callback
        // channel.basicConsume(RabbitMQConfig.QUEUE_NAME, true, consumer);
    }
}

4. 生产端代码

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
 * 生产者
 */
public class MessageProvider {
    public static void main(String[] args) {
        ConnectionFactory factory = new ConnectionFactory();
        // 设置主机IP
        factory.setHost(RabbitMQConfig.HOST);
        // 设置端口
        factory.setPort(RabbitMQConfig.PORT);
        // 设置 Vhost
        factory.setVirtualHost(RabbitMQConfig.VHOST);

        // 设置访问用户
        factory.setUsername(RabbitMQConfig.USERNAME);
        factory.setPassword(RabbitMQConfig.PASSWORD);
        try (
                // 建立连接
                Connection connection = factory.newConnection();
                // 创建Channel消息通道
                Channel channel = connection.createChannel();
        ) {
            // 设置属性,消息5秒后过期
            AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                    .deliveryMode(2)// 持久化消息
                    .contentEncoding("UTF-8")
                    .expiration("5000")// TTL-Time to live
                    .build();

            String msg = "阁下可是常山赵子龙";
            channel.basicPublish(RabbitMQConfig.DIRECT_EXCHANGE, RabbitMQConfig.ROUTING_KEY, properties, msg.getBytes("UTF-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值