rabbitmq简单入门

一、rabbitMq的概念

rabbitMq是一个消息中间件,他接收并且供第三方使用。就像快递一样,商家为生产者,快递站为MQ,而用户为消费者。

二、为什么使用rabbitMq

  1. 解耦
    比如公司的系统A,需要将数据推送到其他不同的系统中去。这样子系统间的耦合度变高,系统A需要考虑一些列乱七八糟的因素,如其他系统挂了,需不需要重新推送、、等待问题。这时候如果使用rabbitMq,则系统A只需要考虑将数据推送到rabbitMq,其他系统需要消费的,自己去系统A获取即可,可以有效的做到系统A与其他系统的解耦。
  2. 削峰
    比如公司的业务存在高峰期,如上午数据写入存在w/s的数据量,而数据库的承受量加入只有k/s,系统就有可能导致崩溃卡死。但是如果将消息写入rabbitmq,由rabbitmq控制消息读取速度小于系统承受量,这样即使在高峰时期也不会挂掉。
  3. 异步
    比如系统A存在需求,如果接受某一份数据,则需要写入A系统和其他系统,时间是累加的。但是如果将数据发送到其他rabbitmq,由各个系统自己实现写入,则写入的时间将会大幅度缩减。

三、使用rabbitMq的缺点

  1. 系统可用性
    由于加入了rabbitmq,导致系统的组件增加,部署与运维难度增加。而且如果rabbitmq挂掉, 也会影响系统的使用。
    2.数据一致性
    因为加入了rabbitmq,需要考虑的因为也会随之增加。比如消息丢失、消息重复消费、消息发送成功却是否被消费者成功消费等等、、、

四、MQ的选择

名称优点缺点适用场景
activeMQ单机吞吐量万级,时效性ms级,可用性高,较低概率出现丢失数据。官方社区现在对于 ActiveMQ 5.x的版本维护越来越少,高吞吐量场景较少使用。早期使用的 ActiveMQ,随着其他MQ的出现使用量渐渐减少,而且没经过大规模吞吐量场景的验证,社区也不是很活跃,所以不推荐。
Kafka单机吞吐量 百万级,时效性 ms级,可用性非常高,消息可靠性可配置 0 丢失。而且是分布式的,一个数据有多个副本,少数机器宕机也不会丢失数据。单机超过64个队列/分区,CPU会明显变高,队列越多越高,发送消息响应时间变长。消费失败不支持重试。主要用于日志的采集与传输,一般大公司使用
RocketMQ单机吞吐量十万级,可用性高,支持分布式,消息可靠性可以做到0丢失,扩展性好,支持十亿级别消息堆积。支持的客户端不多,目前只支持java和c++。主要用于金融领域,被阿里广泛的用于订单、交易、重置、消息推送等场景。
RabbitMQ用erlang语言编写,性能较好,单机吞吐量万级,时效性μs级,可用性高,消息可靠性基本不丢失,而且支持大量的其他语言,社区活跃度高,更新频率高。商业版需要收费,学习成本较高。界面管理方便,功能完备。如果数据量较小可以推荐使用,适用于中小型公司。

五、安装rabbitmq

ps:由于需要的包下载较慢,可以直接从这里下载(网络较好的可以忽略):https://download.csdn.net/download/weixin_40496191/80386784

  1. 由于rabbitmq需要erlang的支持,所以下载包之前需要确定erlangrabbitmq的对应关系:https://www.rabbitmq.com/which-erlang.html
  2. 安装ErLang
    1)下载:wget https://github.com/rabbitmq/erlang-rpm/releases/tag/v21.3.1/erlang-21.3.1-1.el7.x86_64.rpm
    2)安装:rpm -ivh erlang-21.3.1-1.el7.x86_64.rpm
    ps1: 如果安装错误:rabbitmq-server-3.8.8-1.el7.noarch.rpm: 不是 rpm 软件包 (或者没有manifest)。这是因为github网络访问较慢,有可能下载不全,所以如果wget实在有问题,可以选择直接登录网站包下载下来,再传到linux即可!
    ps2:下载的版本el7根据linux来,可通过uname -a查看:在这里插入图片描述
  3. 安装 RabbitMQ
    1)下载依赖:yum install -y socat
    2)下载包:wget https://github.com/rabbitmq/rabbitmq-server/releases/tag/v3.8.8/rabbitmq-server-3.8.8-1.el7.noarch.rpm
    3)安装:rpm -ivh rabbitmq-server-3.8.8-1.el7.noarch.rpm
    ps:如果安装报错,下载不全,解决办法如上!
  4. 启动RabbitMQ: systemctl start rabbitmq-server
  5. 设置RabbitMQ开机自启动: systemctl enable rabbitmq-server
    ps1:相关命令-关闭RabbitMQ:rabbitmqctl stop
    ps2:相关命令-重启RabbitMQ:systemctl restart rabbitmq-server
    ps3:相关命令-插件列表:rabbitmq-plugins list
    ps4:相关命令-启动插件:rabbitmq-plugins enable XXX (XXX为插件名)
    ps5:相关命令-停用插件:rabbitmq-plugins disable XXX
  6. 查看启动后的情况 :rabbitmqctl statussystemctl status rabbitmq-server
    在这里插入图片描述
  7. 新建一个用户
    1)新建用户:rabbitmqctl add_user admin admin
    2)授予管理员权限:rabbitmqctl set_user_tags admin administrator
    3)设置admin可以使用的虚机权限:rabbitmqctl add_vhost admin–>rabbitmqctl set_permissions -p admin admin ".*" ".*" ".*"
  8. 查看用户:rabbitmqctl list_users
    在这里插入图片描述
  9. 重启RabbitMQ:systemctl restart rabbitmq-server
  10. 查看页面:http://192.168.248.10:15672
    在这里插入图片描述
    输入账号密码:admin/admin
    在这里插入图片描述
    进入该界面说明安装成功(这里因为做了一些代码操作,所以界面不是原始的,新安装的跟我的有些不同)

六、RabbitMQ工作原理图

在这里插入图片描述

  1. producer(生产者),即发消息的系统。
  2. connection(连接通道):与RabbitMQ服务器连接的TCP通道
  3. exchange(交换机)和queue(队列):消息先发给交换机,再由交换机根据规则转发给队列。一个交换机可以对应多个队列。如果工作时,不省明交换机,则会使用默认交换机。
  4. consumer(消费者):即最后消费队列消息的系统。

七、代码实现-简单工作

工作流程
在这里插入图片描述

由于我们后续测试都会连接rabbitmq服务器,所以这里创建一个公共连接类。

  1. 创建公共连接类
package com.rabbitmqUtils;

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

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

/**
 * @author 天真热
 * 创建信道
 * @create 2022-02-08 16:26
 * @desc
 **/
public class RabbitmqUtils {
    //队列名称
    public static final String RABBITMQ_QUEUE = "RABBITMQ_QUEUE";
    //交换机名称
    public static final String RABBITMQ_EXCHANGE = "RABBITMQ_EXCHANGE";

    public static Channel getChannel() throws IOException, TimeoutException {
        //创建一个连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //工厂ip
        factory.setHost("192.168.248.10");
        //用户名
        factory.setUsername("admin");
        //密码
        factory.setPassword("admin");
        //创建链接
        Connection connection = factory.newConnection();
        //获取信道
        Channel channel = connection.createChannel();

        return channel;
    }
}

  1. 创建生产者
package com.rabbitmq1;

import com.rabbitmq.client.Channel;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Product {
    //发消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //生成队列,不创建交换机,走默认的交换机
        //1.名称
        //2.队列消息是否持久化(否:存内存,是:存磁盘。默认否)
        //3.队列是否只供一个消费者消费,默认否
        //4.最后一个消费者断开连接后,是否自动删除。
        //5.其他参数
        channel.queueDeclare(RabbitmqUtils.RABBITMQ_QUEUE, true, false, false, null);
        //发消息
        String message = "this is QUEUE_P1";
        //持续发送消息
        for (int i = 0; i < 10; i++) {
            Thread.sleep(1000);
            //1.交换机,简单版本不考虑,直接空字符串,即默认交换机
            //2.路由key,直接写队列名即可
            //3.参数,忽略
            //4.消息体
            channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, null, (message+i).getBytes());
        }

        System.out.println("消息发送成功");
    }
}

  1. 创建消费者
package com.rabbitmq1;

import com.rabbitmq.client.*;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 15:34
 * @desc
 **/
public class Consume {


    //发消息
    public static void main(String[] args) throws IOException, TimeoutException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //消费者未成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答
        //3.消费者成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, true, deliverCallback, cancelCallback);
    }
}

启动生产者类,查看rabbitmq可视化界面,可以发现已经写入了10条
在这里插入图片描述

启动消费者,效果如下,可以看到队列消息已经被消费,则成功!
在这里插入图片描述在这里插入图片描述

ps:如果报错ERROR com.rabbitmq.client.impl.ForgivingExceptionHandler - An unexpected connection driver error occured,则需要admin授权
在这里插入图片描述

八、代码实现-多个消费者

工作原理图
在这里插入图片描述
生产者

package com.rabbitmq2;

import com.rabbitmq.client.Channel;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Product {
    //发消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //0是轮询、1是不公平分发,大于1则是预取值,默认为0。预取后,再进行不公平分发。
        channel.basicQos(0);
        //生成队列,
        //1.名称
        //2.队列消息是否持久化(否:存内存,是:存磁盘。默认否)
        //3.队列是否只供一个消费者消费,默认否
        //4.最后一个消费者断开连接后,是否自动删除。
        //5.其他参数
        channel.queueDeclare(RabbitmqUtils.RABBITMQ_QUEUE, true, false, false, null);
        //持续发送消息
        for (int i = 0; i < 10; i++) {
            String message="this is Product"+i;
            //1.交换机,简单版本不考虑,直接空字符串即可(默认/无名交换机)
            //2.路由key,直接写队列名即可
            //3.参数,忽略
            //4.消息体
            channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, null, message.getBytes());
        }

        System.out.println("消息发送成功");
    }
}


消费者1

package com.rabbitmq2;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * 这是一个工作线程
 *
 * @author 天真热
 * @create 2022-02-08 16:36
 * @desc
 **/
public class Consume01 {
    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException {
        System.out.println("这是工作线程1....");
        Channel channel = RabbitmqUtils.getChannel();

        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答(是则默认成功,否则需要)
        //3.消费者未成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, true, deliverCallback, cancelCallback);
    }
}

消费者2

package com.rabbitmq2;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * 这是一个工作线程
 *
 * @author 天真热
 * @create 2022-02-08 16:36
 * @desc
 **/
public class Consume02 {
    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException {
        System.out.println("这是工作线程2....");
        Channel channel = RabbitmqUtils.getChannel();

        //消费者未成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答
        //3.消费者成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, true, deliverCallback, cancelCallback);
    }
}

启动消费者1,再启动消费者2.然后启动生产者,可以看到,消息是轮询发送给两个消费者。
在这里插入图片描述
在这里插入图片描述

八、代码实现-自动/手动应答

  1. 概念
    1)自动应答:消息从队列发送给消费者时,就已经默认消费成功。
    优点:效率高。
    缺点:一方面如果消费者在消费消息时候如果断开了,则消费者没有成功处理消息,而队列默认消费成功,就会造成数据丢失。另一方面,如果消费者系统性能交叉,没法及时处理消息,就会造成消息积压,内存耗尽而崩溃。
    2)手动应答:消息从队列发送给消费者时,消费者需要手动确认消息,队列才会认为消费成功。
    优点:数据传输较为安全,而且可操作性较高。
    缺点:效率低
  2. 手动应答环境下的可操作性
    1)根据不同消费者应答消息的效率,队列可以动态分配消息给消费者
    2)对于一些特殊的队列信息,可以选择拒收,重新放回队列
  3. 代码实现
    在这里插入图片描述

生产者

package com.rabbitmq3;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Product {
    //发消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //生成队列,
        //1.名称
        //2.队列消息是否持久化(否:存内存,是:存磁盘。默认否)
        //3.队列是否只供一个消费者消费,默认否
        //4.最后一个消费者断开连接后,是否自动删除。
        //5.其他参数
        channel.queueDeclare(RabbitmqUtils.RABBITMQ_QUEUE, true, false, false, null);
        //持续发送消息
        for (int i = 0; i < 10; i++) {
            //发消息
            String message = "this is Product"+i;
            //1.交换机,简单版本不考虑,直接空字符串即可(默认/无名交换机)
            //2.路由key,直接写队列名即可
            //3.参数,(消息持久化,需要队列开启持久化才有效)
            //4.消息体
            channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
        }

        System.out.println("消息发送成功");
    }
}

消费者1(接受,每秒接受1条,初始取5条)

package com.rabbitmq3;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * 这是一个工作线程
 *
 * @author 天真热
 * @create 2022-02-08 16:36
 * @desc
 **/
public class Consume01 {
    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException {
        System.out.println("这是工作线程1....");
        Channel channel = RabbitmqUtils.getChannel();
        //0是轮询,默认值
        //1是不公平分发,即哪个消费者效率高,哪边分配的多
        //大于1则是预取值,即消费者一定会消费的消息数量。预取后,再进行不公平分发。
        channel.basicQos(5);

        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            //睡眠
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));

            //手动应答
            //1.消息确认标记,2.是否批量应答
            channel.basicAck(message.getEnvelope().getDeliveryTag(), false);

        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答(是则默认成功,否则需要)
        //3.消费者未成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, false, deliverCallback, cancelCallback);
    }
}

消费者2(拒收,每10s拒收一条,初始取2条)

package com.rabbitmq3;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * 这是一个工作线程
 *
 * @author 天真热
 * @create 2022-02-08 16:36
 * @desc
 **/
public class Consume02 {
    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException {
        System.out.println("这是工作线程2....");
        Channel channel = RabbitmqUtils.getChannel();
        //0是轮询、1是不公平分发,大于1则是预取值,默认为0。预取后,再进行不公平分发。
        channel.basicQos(2);

        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            //睡眠
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));

            //1.消息否定确认标记,2.消息是否重新被放回队列
            channel.basicReject(message.getEnvelope().getDeliveryTag(), true);

        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答(是则默认成功,否则需要)
        //3.消费者未成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, false, deliverCallback, cancelCallback);
    }
}

可以去rabbitmq界面查看
在这里插入图片描述

结果:
在这里插入图片描述
在这里插入图片描述

九、代码实现-消息发布确认的三种方式

消息发布确认就是指生产者将消息发送到Broker 后,如果 Broker 收到消息,则会给我们生产者一个应答。生产者进行接收应答,用来确定这条消息是否正常的发送到 Broker。对于消息发布确认一共有三种方式。

  1. 单个确认为每发送一次消息就进行一次确认,优点是准确无误,缺点是资源占用较大,速度较慢。1000条数据测试时间为1311ms
    /**
     * 单个确认
     */
    public static void publishDg() throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //开启发布确认
        channel.confirmSelect();
        //开始时间
        long begin = System.currentTimeMillis();
        //发送消息
        for (int i = 0; i < 1000; i++) {
            channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, ("message" + i).getBytes());
            //发布确认
            boolean flag = channel.waitForConfirms();
            if (flag) {
                System.out.println("发送成功");
            }
        }
        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("单独确认花费时间=" + (end - begin));
    }
  1. 批量确认为每发送一批消息再进行一次确认,优点是比单个确认更快,但是无法精确定位到发送失败消息。1000条数据测试时间为170ms
  public static void publishPl() throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //开启发布确认
        channel.confirmSelect();
        //开始时间
        long begin = System.currentTimeMillis();
        //批量确认大小
        int batchSize = 100;
        //批量发送消息、确认
        for (int i = 0; i < 1000; i++) {
            channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, ("message" + i).getBytes());
            if (i % batchSize == 0) {
                channel.waitForConfirms();
            }
        }

        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("单独确认花费时间=" + (end - begin));
    }
  1. 异步确认为在发送前创建一个支持高并发的Map,key存储消息tag,values存储message,并调用监听器进行监听消息发送。一般在每次发送后用Map记录下发送消息,监听器根据结果回调相关函数,若发送成功,回调成功函数,在Map中删去该消息。发送失败,回调失败函数,在失败函数中通过Map显示该消息。异步确认在所有确认中综合性能最佳。1000条数据测试时间为43ms
 public static void publishYb() throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //开启发布确认
        channel.confirmSelect();
        //开始时间
        long begin = System.currentTimeMillis();


        //线程安全有序的一个哈希表,适合高并发的情况
        //1.将序号和消息进行关联
        //2.轻松批量删除条目 只要给到序号
        //3.支持高并发
        ConcurrentSkipListMap<Long, String> concurrentSkipListMap = new ConcurrentSkipListMap<>();

        //--------------------监听器--------------------------
        //消息确认成功回调函数
        //1.消息的标记,2.是否为批量操作
        ConfirmCallback ackCallback = (deliveryTag, multiple) -> {
            //消息接受处理
            if (multiple) {
                //批量
                ConcurrentNavigableMap<Long, String> confirmd = concurrentSkipListMap.headMap(deliveryTag);
                confirmd.clear();
            } else {
                //非批量
                concurrentSkipListMap.remove(deliveryTag);
            }

            System.out.println("确认的消息:" + deliveryTag);
        };

        //消息确认失败回调函数
        //1.消息的标记,2.是否为批量操作
        ConfirmCallback nackCallback = (deliveryTag, multiple) -> {
            //消息未接受处理
            String message = concurrentSkipListMap.get(deliveryTag);
            System.out.println("未确认的消息:" + deliveryTag + ":" + message);
        };

        //消息监听器,监听失败和成功的消息
        channel.addConfirmListener(ackCallback, nackCallback);
        //批量发送消息、确认
        for (int i = 0; i < 1000; i++) {
            String message = ("message" + i);
            channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
            //记录发送的消息
            concurrentSkipListMap.put(channel.getNextPublishSeqNo(), message);
        }

        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("单独确认花费时间=" + (end - begin));
        System.out.println(concurrentSkipListMap.size());

    }

十、代码实现-交换机

前面有说到,实际上生产者发送消息,消息是直接发给交换机,然后再由交换机根据相关规则分配给队列。而根据分配规则,常见的基类交换机分别有:直接交换机(direct),主题交换机(topic),标题交换机(topic),首部交换机(Headers)等。
ps:因为我这里用的是同一个交换机,如果同一个交换机,并且配置修改了,则需要删除原先的交换机,否则会报错。
在这里插入图片描述

  1. 交换机模式一fanout
    这种模式跟广播一样,即发送到交换机的所有消息,都会发到交换机的所有队列中,代码如下:

生产者

package com.rabbitmq5;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Product {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "fanout");

        for (int i = 0; i < 10; i++) {
            String message = "发送的消息" + i;
            //1.交换机,简单版本不考虑,直接空字符串即可(默认/无名交换机)
            //2.路由key,直接写队列名即可
            //3.参数,(消息持久化)
            //4.消息体
            channel.basicPublish(RabbitmqUtils.RABBITMQ_EXCHANGE, "", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
        }
    }
}

消费者1

package com.rabbitmq5;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Consume01 {
    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "fanout");
        //声明一个临时队列
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机和队列的
        channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "");


        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答(是则默认成功,否则需要)
        //3.消费者未成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(queueName, true, deliverCallback, cancelCallback);

    }
}

消费者2:

package com.rabbitmq5;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Consume02 {
    //发消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "fanout");
        //声明一个临时队列
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机和队列的
        channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "");


        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答(是则默认成功,否则需要)
        //3.消费者未成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(queueName, true, deliverCallback, cancelCallback);

    }
}

结果
在这里插入图片描述
在这里插入图片描述
2. 交换机模式之direct
这种方式相对于fanout来说增加了一定的限制,即消息只能够发送到交换机的固定rountKey的队列中去。代码如下:
生产者:

package com.rabbitmq6;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Product {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机
//        channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "direct");

        for (int i = 0; i < 10; i++) {
            String message = "发送的消息" + i;
            //1.交换机,简单版本不考虑,直接空字符串即可(默认/无名交换机)
            //2.路由key,直接写队列名即可
            //3.参数,(消息持久化)
            //4.消息体
            channel.basicPublish(RabbitmqUtils.RABBITMQ_EXCHANGE, "error", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
        }
    }
}

消费者1:

package com.rabbitmq6;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Consume01 {
    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "direct");
        //声明一个临时队列
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机和队列的
        channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "info");
        channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "warning");


        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答(是则默认成功,否则需要)
        //3.消费者未成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(queueName, true, deliverCallback, cancelCallback);
 		System.out.println("队列info/warning等待...");
    }
}

消费者2

package com.rabbitmq6;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Consume01 {
    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "direct");
        //声明一个临时队列
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机和队列的
        channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "info");
        channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "warning");


        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答(是则默认成功,否则需要)
        //3.消费者未成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(queueName, true, deliverCallback, cancelCallback);
		System.out.println("队列error等待...");
    }
}
       

在这里插入图片描述
在这里插入图片描述
3. 交换机模式之topic
前面说的direct模式实际上就是rountkey绝对匹配。而topic是rountkey的模糊匹配。
*(星号)代表一个单词
#(井号)可以替代零个或多个单词
代码如下:
生产者

package com.rabbitmq7;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Product {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "topic");

        for (int i = 0; i < 10; i++) {
            String message = "发送的消息" + i;
            //1.交换机,简单版本不考虑,直接空字符串即可(默认/无名交换机)
            //2.路由key,直接写队列名即可
            //3.参数,(消息持久化)
            //4.消息体
            channel.basicPublish(RabbitmqUtils.RABBITMQ_EXCHANGE, "queue.queue.queue11", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
        }
    }
}

消费者1

package com.rabbitmq7;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Consume01 {
    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "topic");
        //声明一个临时队列
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机和队列的
        channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "*.queue.*");


        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答(是则默认成功,否则需要)
        //3.消费者未成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(queueName, true, deliverCallback, cancelCallback);
        System.out.println("消费者|*.queue.*|等待中....");
    }
}

消费者2

package com.rabbitmq7;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Consume02 {
    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机
        channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "topic");
        //声明一个临时队列
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机和队列的
        channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "queue.*.*");


        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答(是则默认成功,否则需要)
        //3.消费者未成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(queueName, true, deliverCallback, cancelCallback);
        System.out.println("消费者|queue.*.*|等待中....");
    }
}

效果
在这里插入图片描述
在这里插入图片描述

十一、代码实现-优先级队列

队列的消费顺序一般是先进先出。但是在某些订单中业务中,我们需要给vip用户后下单,先出货的特殊权限,这时候就需要用到优先级队列。
原理,在原来先进先出的逻辑上,给队列备注优先级,最后的顺序如下:
优先级高–>优先级低–>没有备注优先级
ps:优先级的范围为0-255
生产者

package com.rabbitmq12;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Product {
    //队列名称
    public static final String ORDER_QUEUE = "ORDER_QUEUE";

    //发消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //参数
        Map<String, Object> argument = new HashMap<>();
        argument.put("x-max-priority", 10);//设置优先级范围0-10,官方允许值是0-255。设置过大会浪费内存

        //生成队列,
        //不创建交换机,走默认的交换机
        //1.名称
        //2.队列消息是否持久化(否:存内存,是:存磁盘。默认否)
        //3.队列是否只供一个消费者消费,默认否
        //4.最后一个消费者断开连接后,是否自动删除。
        //5.其他参数
        channel.queueDeclare(ORDER_QUEUE, true, false, false, argument);
        //发消息
        String message = "this is QUEUE_P";
        //持续发送消息
        for (int i = 0; i < 10; i++) {
            //1.交换机,简单版本不考虑,直接空字符串即可(默认/无名交换机)
            //2.路由key,直接写队列名即可
            //3.参数,忽略
            //4.消息体
            if (i == 5) {
                AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().priority(5).build();
                channel.basicPublish("", ORDER_QUEUE, properties, (message + i).getBytes());
            } else {
                channel.basicPublish("", ORDER_QUEUE, null, (message + i).getBytes());
            }

        }

        System.out.println("消息发送成功");
    }
}

消费者

package com.rabbitmq12;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 15:34
 * @desc
 **/
public class Consume {
    //队列名称
    public static final String ORDER_QUEUE = "ORDER_QUEUE";

    //发消息
    public static void main(String[] args) throws IOException, TimeoutException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //消费者未成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        //1.队列名
        //2.消费成功后是否自动应答
        //3.消费者成功消费时候的回调
        //4.消费者取消消费的回调方法
        channel.basicConsume(ORDER_QUEUE, true, deliverCallback, cancelCallback);
    }
}

测试,启动生产者,再启动消费者
在这里插入图片描述

十二、代码实现-死信队列

死信指的是无法被消费的消息。这些消息因为一些如网络超时等原因,导致无法被消费,就成了死信消息。所以为了保证这些数据不丢失,就有了死信队列,专门对死信消息进行处理。
工作图:
在这里插入图片描述

代码如下:
生成者:

package com.rabbitmq8;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.MessageProperties;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Product {
    //正常交换机
    public static String NORMAL_EXCHANGE = "NORMAL_EXCHANGE";

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明一个交换机(不需要重复声明)
        //channel.exchangeDeclare(NORMAL_EXCHANGE, "direct");

        //设置ttl时间为10s,过期则进入死信队列
        AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build();

        //发送死信消息
        for (int i = 0; i < 10; i++) {
            String message = "发送的消息" + i;
            //1.交换机,简单版本不考虑,直接空字符串即可(默认/无名交换机)
            //2.路由key,直接写队列名即可
            //3.参数,(消息持久化)
            //4.消息体
            channel.basicPublish(NORMAL_EXCHANGE, "normalQueue", properties, message.getBytes());
        }
    }
}

消费者(正常队列)

package com.rabbitmq8;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Consume01 {
    //正常交换机
    public static String NORMAL_EXCHANGE = "NORMAL_EXCHANGE";
    //死信交换机
    public static String DEAD_EXCHANGE = "DEAD_EXCHANGE";
    //正常队列
    public static String NORMAL_QUEUE = "NORMAL_QUEUE";
    //死信队列
    public static String DEAD_QUEUE = "DEAD_QUEUE";

    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();
        //声明普通和死信交换机
        channel.exchangeDeclare(NORMAL_EXCHANGE, "direct");
        channel.exchangeDeclare(DEAD_EXCHANGE, "direct");

        //声明死信队列
        channel.queueDeclare(DEAD_QUEUE, false, false, false, null);


        //设置参数
        Map<String, Object> arguments = new HashMap<>();
        //设置死信交换机
        arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE);
        //设置死信RoutingKey
        arguments.put("x-dead-letter-routing-key", "deadQueue");
        //设置正常队列长度
        arguments.put("x-max-length", 6);
        //设置过期时间,10s(一般不在这里设置,而是在生产者端配置,这样子过期时间可以由生产者随意改动)
        //arguments.put("x-message-ttl", "10000");
        //声明普通队列
        channel.queueDeclare(NORMAL_QUEUE, false, false, false, arguments);

        //绑定普通交换机和队列的
        channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, "normalQueue");
        //绑定死信交换机和队列的
        channel.queueBind(DEAD_QUEUE, DEAD_EXCHANGE, "deadQueue");


        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("拒绝");
            //拒绝,并且不放回队列
            channel.basicReject(message.getEnvelope().getDeliveryTag(), false);
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        channel.basicConsume(NORMAL_QUEUE, false, deliverCallback, cancelCallback);
        System.out.println("正常队列准备消费消息......");
    }
}

消费者2(死信队列)

package com.rabbitmq8;

import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmqUtils.RabbitmqUtils;

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

/**
 * @author 天真热
 * @create 2022-02-08 14:52
 * @desc
 **/
public class Consume02 {
    //死信队列
    public static String DEAD_QUEUE = "DEAD_QUEUE";

    //接收消息
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        //获取信道
        Channel channel = RabbitmqUtils.getChannel();

        //消费者成功消费时候的回调方法
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("消费者成功消费时候的回调" + new String(message.getBody()));
        };
        //消费者取消消费的回调方法
        CancelCallback cancelCallback = consumerTag -> {
            System.out.println("消费者取消消费的回调方法");
        };

        //消费消息
        channel.basicConsume(DEAD_QUEUE, true, deliverCallback, cancelCallback);
        System.out.println("死信队列准备消费消息......");
    }
}

测试1:首先先运行死信队列,然后运行生产者。由于生产的消息没有被消费掉,消息超时自动进入死信队列
在这里插入图片描述
测试二:运行死信队列和正常队列,然后运行生产者。由于生产的消息被拒绝,消息超时自动进入死信队列
在这里插入图片描述
在这里插入图片描述

十三、代码实现-延迟队列

延迟队列:延迟队列里面的元素,是到达指定时候后,就对这些元素进行处理。如果订单功能,如果指定时间内不进行支付,则会取消订单。
原理图:
在这里插入图片描述
因为我们后续rabbitmq肯定是要在springboot框架运行,所以这里需要整合springboot。

  1. 在yml配置文件配置
spring:
  rabbitmq:
    host: 192.168.248.10
    port: 5672
    username: admin
    password: admin
    #交换机确认接口
    publisher-confirms: true
  1. 添加配置类
package com.rabbitmq9;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 天真热
 * @create 2022-02-10 10:09
 * @desc
 **/
@Configuration
public class Config {
    //普通交换机
    public static final String X_EXCHANGE = "X";
    //死信交换机
    public static final String Y_DEAD_LETTER_EXCHANGE = "Y";
    //普通队列名称
    public static final String QUEUE_A = "QA";
    public static final String QUEUE_B = "QB";
    public static final String QUEUE_C = "QC";
    //死信队列名称
    public static final String DEAD_LETTER_QUEUE = "QD";

    //声明xExchange 别名
    @Bean("xExchange")
    public DirectExchange xExchange() {
        return new DirectExchange(X_EXCHANGE);
    }

    //声明yExchange 别名
    @Bean("yExchange")
    public DirectExchange yExchange() {
        return new DirectExchange(Y_DEAD_LETTER_EXCHANGE);
    }

    //声明普通队列A ttl 为10s
    @Bean("queueA")
    public Queue queuA() {
        Map<String, Object> argument = new HashMap<>();
        //设置死信交换机
        argument.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);
        //设置死信RoutingKey
        argument.put("x-dead-letter-routing-key", "YD");
        //设置ttl,10s
        argument.put("x-message-ttl", 10000);
        //创建队列
        return QueueBuilder.durable(QUEUE_A).withArguments(argument).build();
    }

    //声明普通队列B ttl 为10s
    @Bean("queueB")
    public Queue queuB() {
        Map<String, Object> argument = new HashMap<>();
        //设置死信交换机
        argument.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);
        //设置死信RoutingKey
        argument.put("x-dead-letter-routing-key", "YD");
        //设置ttl,40s
        argument.put("x-message-ttl", 40000);
        //创建队列
        return QueueBuilder.durable(QUEUE_B).withArguments(argument).build();
    }

    //声明普通队列C ttl 为生产者确定
    @Bean("queueC")
    public Queue queuC() {
        Map<String, Object> argument = new HashMap<>();
        //设置死信交换机
        argument.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);
        //设置死信RoutingKey
        argument.put("x-dead-letter-routing-key", "YD");
        //创建队列
        return QueueBuilder.durable(QUEUE_C).withArguments(argument).build();
    }

    //死信队列
    @Bean("queueD")
    public Queue queuD() {
        //创建队列
        return QueueBuilder.durable(DEAD_LETTER_QUEUE).build();
    }

    //绑定队列A
    @Bean
    public Binding queueABindingX(@Qualifier("queueA") Queue queueA, @Qualifier("xExchange") DirectExchange xExchange) {
        return BindingBuilder.bind(queueA).to(xExchange).with("XA");
    }

    //绑定队列B
    @Bean
    public Binding queueBBindingX(@Qualifier("queueB") Queue queueB, @Qualifier("xExchange") DirectExchange xExchange) {
        return BindingBuilder.bind(queueB).to(xExchange).with("XB");
    }

    //绑定队列C
    @Bean
    public Binding queueCBindingX(@Qualifier("queueC") Queue queueC, @Qualifier("xExchange") DirectExchange xExchange) {
        return BindingBuilder.bind(queueC).to(xExchange).with("XC");
    }

    //绑定队列D
    @Bean
    public Binding queueDBindingY(@Qualifier("queueD") Queue queueD, @Qualifier("yExchange") DirectExchange yExchange) {
        return BindingBuilder.bind(queueD).to(yExchange).with("YD");
    }




}

  1. 添加生产消息类
package com.rabbitmq9;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 天真热
 * @create 2022-02-10 15:03
 * @desc
 **/
@Slf4j
@RestController
@RequestMapping("/ttl")
public class SendMessageController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/sendMsg/{message}")
    public void sendMessage(@PathVariable String message) {
        log.info("发送消息");
        rabbitTemplate.convertAndSend("X", "XA", "消息来自10s的ttl:" + message);
        rabbitTemplate.convertAndSend("X", "XB", "消息来自40s的ttl:" + message);

    }

    @GetMapping("/sendExpireMsg/{message}/{ttlTime}")
    public void sendExpireMsg(@PathVariable String message, @PathVariable String ttlTime) {
        log.info("发送定时消息");
        rabbitTemplate.convertAndSend("X", "XC", "消息来自定时消息:" + message, msg -> {
            //发消息的时候,延迟延长
            msg.getMessageProperties().setExpiration(ttlTime);
            return msg;
        });

    }
}

  1. 添加消费者类
package com.rabbitmq9;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 队列ttl消费者
 *
 * @author 天真热
 * @create 2022-02-10 16:00
 * @desc
 **/
@Slf4j
@Component
public class Consume {
    //接收消息
    @RabbitListener(queues = Config.DEAD_LETTER_QUEUE)
    public void receiveD(Message msg, Channel channel) {
        String message = new String(msg.getBody());
        log.info("接收到了延迟队列消息:" + message);
    }
}

测试1:http://localhost:8090/ttl/sendMsg/hahaha
在这里插入图片描述
测试2:http://localhost:8090/ttl/sendExpireMsg/5555/100
在这里插入图片描述
测试3:连续发送两个地址。可以看到延迟消息需要排队,没法优先发送延时时间短的,这是个弊端,可以使用插件克服这个问题。
http://localhost:8090/ttl/sendExpireMsg/5555/10000
http://localhost:8090/ttl/sendExpireMsg/558885/1000
在这里插入图片描述

十四、代码实现-RabbitMQ插件实现延迟队列

安装教程

  1. 下载:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/tag/v3.8.0
  2. 将插件放入:/usr/lib/rabbitmq/lib/rabbitmq_server-3.8.8/plugins下
  3. 进入目录:cd /usr/lib/rabbitmq/lib/rabbitmq_server-3.8.8/plugins
  4. 安装:rabbitmq-plugins enable rabbitmq_delayed_message_exchange
  5. 重启:systemctl restart rabbitmq-server
    在这里插入图片描述
    工作原理:
    在这里插入图片描述
    代码如下
    配置类
package com.rabbitmq10;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.CustomAutowireConfigurer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 天真热
 * @create 2022-02-10 10:09
 * @desc
 **/
@Configuration
public class DelayConfig {
    //队列
    public static final String DELAY_QUEUE = "DELAY_QUEUE";
    //交换机
    public static final String DELAY_EXCHANGE = "DELAY_EXCHANGE";
    //routingKey
    public static final String DELAY_ROUNTING_KEY = "DELAY_ROUNTING_KEY";


    //声明交换机
    @Bean
    public CustomExchange delayEchange() {
        Map<String, Object> arguments = new HashMap<>();
        arguments.put("x-delayed-type", "direct");
        //1.交换机名称
        //2.交换机类型
        //3.是否需要持久化
        //4.是否需要自动删除
        //5.其他参数
        return new CustomExchange(DELAY_EXCHANGE, "x-delayed-message", true, false, arguments);
    }


    //声明队列
    @Bean
    public Queue delayQueue() {
        //创建队列
        return new Queue(DELAY_QUEUE);
    }


    //绑定队列
    @Bean
    public Binding delayBindingQueue(@Qualifier("delayQueue") Queue delayQueue, @Qualifier("delayEchange") CustomExchange delayEchange) {
        return BindingBuilder.bind(delayQueue).to(delayEchange).with("DELAY_ROUNTING_KEY").noargs();
    }

}

消费者

package com.rabbitmq10;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 队列ttl消费者
 *
 * @author 天真热
 * @create 2022-02-10 16:00
 * @desc
 **/
@Slf4j
@Component
public class DelayConsume {
    //接收消息
    @RabbitListener(queues = DelayConfig.DELAY_QUEUE)
    public void receiveDelay(Message msg) {

        String message = new String(msg.getBody());
        log.info("接收到了插件延迟队列消息:" + message);
    }
}

发送消息类

package com.rabbitmq10;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 天真热
 * @create 2022-02-10 15:03
 * @desc
 **/
@Slf4j
@RestController
@RequestMapping("/delayed")
public class SendDelayMessageController {

    @Autowired
    private RabbitTemplate rabbitTemplate;


    @GetMapping("/sendExpireMsg/{message}/{ttlTime}")
    public void sendExpireMsg(@PathVariable String message, @PathVariable Integer ttlTime) {
        log.info("发送定时消息");
        rabbitTemplate.convertAndSend(DelayConfig.DELAY_EXCHANGE, DelayConfig.DELAY_ROUNTING_KEY, "消息来自定时消息:" + message, msg -> {
            //发消息的时候,延迟时长
            msg.getMessageProperties().setDelay(ttlTime);
            return msg;
        });

    }
}

测试:依次执行以下两个地址,可以发现延迟时间短的会先执行,不需要排队
http://localhost:8090/delayed/sendExpireMsg/10000/10000
http://localhost:8090/delayed/sendExpireMsg/500/500
在这里插入图片描述

十五、代码实现-发布确认高级

原理图
在这里插入图片描述
配置文件

spring:
  rabbitmq:
    host: 192.168.248.10
    port: 5672
    username: admin
    password: admin
    #交换机确认接口
    publisher-confirms: true
    #新版本:spring.rabbitmq.publisher-confirm-type=correlated
    #路由回退消息给生产者
    publisher-returns: true

发送消息类

package com.rabbitmq11;

import com.rabbitmq10.DelayConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.CorrelationDataPostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 天真热
 * @create 2022-02-10 15:03
 * @desc
 **/
@Slf4j
@RestController
@RequestMapping("/confirm")
public class SendConfirmMessageController {

    @Autowired
    private RabbitTemplate rabbitTemplate;


    @GetMapping("/sendMsgToBadExchange/{message}")
    public void sendMsgToBadExchange(@PathVariable String message) {
        //类,可以在队列接收消息的时候接受
        CorrelationData correlationData = new CorrelationData("1");
        //发送消息
        rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE + "bad", ConfirmConfig.CONFIRM_ROUNTING_KEY, "消息来自定时消息:" + message, correlationData);
        log.info("发送消息");
    }

    @GetMapping("/sendMsgToBadRounting/{message}")
    public void sendMsgToBadRounting(@PathVariable String message) {
        //类,可以在队列接收消息的时候接受
        CorrelationData correlationData = new CorrelationData("1");
        //发送消息
        rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE, ConfirmConfig.CONFIRM_ROUNTING_KEY + "bad", "消息来自定时消息:" + message, correlationData);
        log.info("发送消息");
    }

    @GetMapping("/sendMsg/{message}")
    public void sendMsg(@PathVariable String message) {
        //类,可以在队列接收消息的时候接受
        CorrelationData correlationData = new CorrelationData("1");
        //发送消息
        rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE, ConfirmConfig.CONFIRM_ROUNTING_KEY , "消息来自定时消息:" + message, correlationData);
        log.info("发送消息");
    }

}

配置类

package com.rabbitmq11;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * 发布确认
 *
 * @author 天真热
 * @create 2022-02-10 10:09
 * @desc
 **/
@Configuration
public class ConfirmConfig {
    //队列
    public static final String CONFIRM_QUEUE = "CONFIRM_QUEUE";
    //交换机
    public static final String CONFIRM_EXCHANGE = "CONFIRM_EXCHANGE";
    //routingKey
    public static final String CONFIRM_ROUNTING_KEY = "CONFIRM_ROUNTING_KEY";
    //备份交换机
    public static final String BACKUP_EXCHANGE = "BACKUP_EXCHANGE";
    //备份队列
    public static final String BACKUP_QUEUE = "BACKUP_QUEUE";
    //告警队列
    public static final String WARNING_QUEUE = "WARNING_QUEUE";


    //声明交换机
    //这里因为用的是之前的交换机,所以需要删除原先的交换机才能生效
    @Bean
    public DirectExchange confirmEchange() {
        return (DirectExchange) ExchangeBuilder.directExchange(CONFIRM_EXCHANGE).durable(true).withArgument("alternate-exchange", BACKUP_EXCHANGE).build();
    }

    //声明备份交换机
    @Bean
    public FanoutExchange backupEchange() {
        return new FanoutExchange(BACKUP_EXCHANGE);
    }


    //声明队列
    @Bean
    public Queue confirmQueue() {
        //创建队列
        return new Queue(CONFIRM_QUEUE);
    }

    //声明备份队列
    @Bean
    public Queue backupQueue() {
        //创建队列
        return new Queue(BACKUP_QUEUE);
    }

    //声明报警队列
    @Bean
    public Queue warningQueue() {
        //创建队列
        return new Queue(WARNING_QUEUE);
    }


    //绑定队列
    @Bean
    public Binding confirmBindingQueue(@Qualifier("confirmQueue") Queue confirmQueue, @Qualifier("confirmEchange") DirectExchange confirmEchange) {
        return BindingBuilder.bind(confirmQueue).to(confirmEchange).with(CONFIRM_ROUNTING_KEY);
    }

    //绑定备份队列
    @Bean
    public Binding backupBindingQueue(@Qualifier("backupQueue") Queue backupQueue, @Qualifier("backupEchange") FanoutExchange backupEchange) {
        return BindingBuilder.bind(backupQueue).to(backupEchange);
    }

    //绑定报警队列
    @Bean
    public Binding warningBindingQueue(@Qualifier("warningQueue") Queue warningQueue, @Qualifier("backupEchange") FanoutExchange backupEchange) {
        return BindingBuilder.bind(warningQueue).to(backupEchange);
    }

}

告警配置类

package com.rabbitmq11;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 回调接口
 *
 * @author 天真热
 * @create 2022-02-11 15:25
 * @desc
 **/
@Component
@Slf4j
public class CallBack implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    //注入
    @PostConstruct
    private void init() {
        //注入
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }

    /**
     * 交换机回调方法(针对于交换机是否成功接收消息)
     * 1.发消息 交换机接收到了 回调
     * 1.1 correlationData 保存回调消息的id及相关信息
     * 1.2 交换机收到消息 ack=true
     * 1.3 call null
     * 2. 发消息 交换机失败了 回调
     * 2.1 correlationData 保存回调消息的id及相关信息
     * 2.2 交换机收到消息 ack=false
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id = correlationData != null ? correlationData.getId() : "";
        if (ack) {
            System.out.println("交换机接受成功了");
        } else {
            System.out.println("交换机接受失败了");
        }

    }

    /**
     * 消息不可达到目的地时,返回给生产者
     *
     * @param message    消息
     * @param replayCode 失败码
     * @param replayText 失败原因
     * @param exchanges  交换机
     * @param routingKey 路由
     */
    @Override
    public void returnedMessage(Message message, int replayCode, String replayText, String exchanges, String routingKey) {
        System.out.println("队列接受失败了");
        System.out.println("消息:" + message + ";消息码:" + replayCode + ";原因:" + replayText + ";交换机:" + exchanges + ";路由:" + routingKey);
    }
}

正常消费者

package com.rabbitmq11;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * 发布确认
 *
 * @author 天真热
 * @create 2022-02-10 10:09
 * @desc
 **/
@Configuration
public class ConfirmConfig {
    //队列
    public static final String CONFIRM_QUEUE = "CONFIRM_QUEUE";
    //交换机
    public static final String CONFIRM_EXCHANGE = "CONFIRM_EXCHANGE";
    //routingKey
    public static final String CONFIRM_ROUNTING_KEY = "CONFIRM_ROUNTING_KEY";
    //备份交换机
    public static final String BACKUP_EXCHANGE = "BACKUP_EXCHANGE";
    //备份队列
    public static final String BACKUP_QUEUE = "BACKUP_QUEUE";
    //告警队列
    public static final String WARNING_QUEUE = "WARNING_QUEUE";


    //声明交换机
    //这里因为用的是之前的交换机,所以需要删除原先的交换机才能生效
    @Bean
    public DirectExchange confirmEchange() {
        return (DirectExchange) ExchangeBuilder.directExchange(CONFIRM_EXCHANGE).durable(true).withArgument("alternate-exchange", BACKUP_EXCHANGE).build();
    }

    //声明备份交换机
    @Bean
    public FanoutExchange backupEchange() {
        return new FanoutExchange(BACKUP_EXCHANGE);
    }


    //声明队列
    @Bean
    public Queue confirmQueue() {
        //创建队列
        return new Queue(CONFIRM_QUEUE);
    }

    //声明备份队列
    @Bean
    public Queue backupQueue() {
        //创建队列
        return new Queue(BACKUP_QUEUE);
    }

    //声明报警队列
    @Bean
    public Queue warningQueue() {
        //创建队列
        return new Queue(WARNING_QUEUE);
    }


    //绑定队列
    @Bean
    public Binding confirmBindingQueue(@Qualifier("confirmQueue") Queue confirmQueue, @Qualifier("confirmEchange") DirectExchange confirmEchange) {
        return BindingBuilder.bind(confirmQueue).to(confirmEchange).with(CONFIRM_ROUNTING_KEY);
    }

    //绑定备份队列
    @Bean
    public Binding backupBindingQueue(@Qualifier("backupQueue") Queue backupQueue, @Qualifier("backupEchange") FanoutExchange backupEchange) {
        return BindingBuilder.bind(backupQueue).to(backupEchange);
    }

    //绑定报警队列
    @Bean
    public Binding warningBindingQueue(@Qualifier("warningQueue") Queue warningQueue, @Qualifier("backupEchange") FanoutExchange backupEchange) {
        return BindingBuilder.bind(warningQueue).to(backupEchange);
    }

}

告警消费者

package com.rabbitmq11;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 队列ttl消费者
 *
 * @author 天真热
 * @create 2022-02-10 16:00
 * @desc
 **/
@Slf4j
@Component
public class WarningConsume {
    //接收消息
    @RabbitListener(queues = ConfirmConfig.WARNING_QUEUE)
    public void receiveDelay(Message msg) {

        String message = new String(msg.getBody());
        log.info("报警发现不可路由的消息:" + message);
    }
}

备份消费者

package com.rabbitmq11;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 队列ttl消费者
 *
 * @author 天真热
 * @create 2022-02-10 16:00
 * @desc
 **/
@Slf4j
@Component
public class BackupConsume {
    //接收消息
    @RabbitListener(queues = ConfirmConfig.BACKUP_QUEUE)
    public void receiveDelay(Message msg) {

        String message = new String(msg.getBody());
        log.info("走的是备份交换机消息:" + message);
    }
}

测试1-正常访问:http://localhost:8090/confirm/sendMsg/100
在这里插入图片描述
测试2-访问错误的路由:http://localhost:8090/confirm/sendMsgToBadExchange/100
在这里插入图片描述
测试3-访问错误的rountingKey:http://localhost:8090/confirm/sendMsgToBadRounting/100
在这里插入图片描述

十六、RabbitMq的界面Features属性介绍

在这里插入图片描述

  1. D:d 是 durable 的缩写,代表这个队列中的消息支持持久化。
  2. AD:ad 是 autoDelete 的缩写。代表当前队列的最后一个消费者退订时被自动删除。注意:此时不管队列中是否还存在消息,队列都会删除。
  3. excl:是 exclusive 的缩写。代表这是一个排他队列。如果一个队列被声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除。这里需要注意三点:其一,排他队列是基于连接可见的,同一连接的不同信道是可以同时访问同一个连接创建的排他队列的。其二,“首次”,如果一个连接已经声明了一个排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同。其三,即使该队列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除的。这种队列适用于只限于一个客户端发送读取消息的应用场景。
  4. Args:是 arguments 的缩写。代表该队列配置了 arguments 参数。
  5. TTL:是 x-message-ttl 的缩写。设置队列中的所有消息的生存周期(统一为整个队列的所有消息设置生命周期), 也可以在发布消息的时候单独为某个消息指定剩余生存时间,单位毫秒。
  6. Exp:Auto Expire,是 x-expires 配置的缩写。当队列在指定的时间没有被访问(consume, basicGet, queueDeclare…)就会被删除,Features=Exp。注意这里是删除队列,不是队列中的消息。
  7. Lim:说明该队列配置了 x-max-length。限定队列的消息的最大值长度,超过指定长度将会把最早的几条删除掉。
  8. Lim B:说明队列配置了 x-max-length-bytes。限定队列最大占用的空间大小, 一般受限于内存、磁盘的大小。
  9. DLX:说明该队列配置了 x-dead-letter-exchange。当队列消息长度大于最大长度、或者过期的等,将从队列中删除的消息推送到指定的交换机中去而不是丢弃掉。
  10. DLK:x-dead-letter-routing-key 的缩写,将删除的消息推送到指定交换机的指定路由键的队列中去。
  11. Pri:x-max-priority 的缩写,优先级队列。表明该队列支持优先级,先定义最大优先级值(定义最大值一般不要太大),在发布消息的时候指定该消息的优先级, 优先级更高(数值更大的)的消息先被消费。
  12. Ovfl:x-overflow 的缩写。队列中的消息溢出时,如何处理这些消息。要么丢弃队列头部的消息,要么拒绝接收后面生产者发送过来的所有消息。有两个配置项:drop-head,代表丢弃队列头部的消息,默认行为;reject-publish 设置队列中的消息溢出后,该队列的行为:”拒绝接收”(所有消息)。
  13. ha-all:镜像队列。all 表示镜像到集群上的所有节点,ha-params 参数忽略。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值