【RabbitMQ】——队列模式(2)

本文介绍了RabbitMQ中的三种消息模式:订阅模式、路由模式和通配符模式。通过实例代码展示了如何实现消息的发布与接收,并解释了不同模式的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        本篇博客接着上一篇介绍MQ的队列模式。
订阅模式
 
        P:生产者
        c1、c2:消费者
        红色:消息队列
        x:交换机


        这种模式猛地一看和Work模式很像,但是这个模式中的每个消费者都有自己的队列,同时引入了一个新的概念——交换机。
        交互机分别绑定生产者和消息队列,生产者发送的消息会经过交换机到达队列,这样可以实现一个消息被多个消费者获取的目的。


注意
        如果交换机没有绑定队列,生产者发送的消息会丢失,因为交互机没有存储消息的能力,消息只能存在队列之中。



生产者代码:
public class Send {
    private final static String EXCHANGE_NAME = "test_exchange_fanout";
    public static void main(String[] argv) throws Exception {
        // 获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        // 声明交换机(exchange)
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");   
        String message = "Hello World"; // 消息内容
        // 将消息发送到交换机
        channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
        System.out.println(" [x] Sent '" + message + "'");
        channel.close();
        connection.close();
    }
}


消费者一代码:
public class Recv {

    private final static String QUEUE_NAME = "test_queue_fanout_1";
    private final static String EXCHANGE_NAME = "test_exchange_fanout";
    public static void main(String[] argv) throws Exception {
        // 获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        // 声明队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        // 绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        // 定义队列的消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 监听队列,手动返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);
        // 获取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" 前台系统: '" + message + "'");
            Thread.sleep(10);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}


消费者二代码:
public class Recv2 {

    private final static String QUEUE_NAME = "test_queue_fanout_2";
    private final static String EXCHANGE_NAME = "test_exchange_fanout";
    public static void main(String[] argv) throws Exception {
        // 获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        // 声明队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        // 绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");


        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        // 定义队列的消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 监听队列,手动返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);
        // 获取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" 搜索系统: '" + message + "'");
            Thread.sleep(10);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

        以上消费者一和消费者二种分别声明了自己的队列,都绑定到了同一个在生成者端声明的交换机中。
        生产者发送一条消息到交换机,绑定到了交换机的队列都可以获得这条消息,实现一条消息被多个消费者获得的功能。


        在RabbitMQ的管理工具中可以查看绑定到交换机的队列,如下:
 

路由模式
 


        路由模式中的元素和订阅者模式中的元素一样,但是路由模式是在订阅者模式基础上的升级。订阅者模式中的队列绑定了交换机后会接受生成者发送的所有消息,但是消费者可能并不想接受所有的消息,路由模式可以实现消息的订制。
        路由模式在生产者发送消息时会声明一个key,消费者的队列在绑定交换机是会表明自己接受什么key值的消息,下面来看一下代码:


生产者代码:

public class Send {
    private final static String EXCHANGE_NAME = "test_exchange_direct";
    public static void main(String[] argv) throws Exception {
        // 获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        // 声明exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");
        // 消息内容
        String message1 = "删除信息, id = 1001";
        String message2 = "更新信息, id = 1002";
        // 发送消息,声明消息的key
        channel.basicPublish(EXCHANGE_NAME, "delete", null, message1.getBytes());
        channel.basicPublish(EXCHANGE_NAME, "update", null, message2.getBytes());
        System.out.println(" [x] Sent '" + message1 + "'");
        System.out.println(" [x] Sent '" + message2 + "'");
        channel.close();
        connection.close();
    }
}

消费者代码:
public class Recv {
    private final static String QUEUE_NAME = "test_queue_direct_1";
    private final static String EXCHANGE_NAME = "test_exchange_direct";
    public static void main(String[] argv) throws Exception {
        // 获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();


        // 声明队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        // 绑定队列到交换机,声明接受消息的key 
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "delete");
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        // 定义队列的消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 监听队列,手动返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);
        // 获取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" 前台系统: '" + message + "'");
            Thread.sleep(10);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

        生产者发送了两条消息,一条key为delete,另一条key为update。在消费者端,队列绑定交互机时声明了delete这个key,这样当前消费者只会接受到delete消息,不会接收到奥update消息。


通配符模式
 


        通配符模式中的元素和订阅者模式及路由模式中的元素一样,而通配符模式是在路由模式基础上的升级。路由模式需要消费者端的队列在绑定交换机时声明完整的key,如果需要接受多个key的消息则需要绑定多条。通配符模式就类似模糊匹配,只需要声明部分关键字即可。


通配符有两种:# 和 *
        #:可以匹配一个或多个词
        *:只能匹配一个词
例:
        item.category.add,使用#写为item.#即可匹配到,使用*则需写为item.*.*


生产者代码:
public class Send {
    private final static String EXCHANGE_NAME = "test_exchange_topic";
    public static void main(String[] argv) throws Exception {
        // 获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        // 声明exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");
        // 消息内容
        String message1 = "删除,id = 1001";
        String message2 = "更新,id = 1002";
        channel.basicPublish(EXCHANGE_NAME, "item.delete", null, message1.getBytes());
        channel.basicPublish(EXCHANGE_NAME, "item.update", null, message2.getBytes());
        System.out.println(" [x] Sent '" + message1 + "'");
        System.out.println(" [x] Sent '" + message2 + "'");
        channel.close();
        connection.close();
    }
}

消费者代码:
public class Recv2 {
    private final static String QUEUE_NAME = "test_queue_topic_2";
    private final static String EXCHANGE_NAME = "test_exchange_topic";
    public static void main(String[] argv) throws Exception {
        // 获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        // 声明队列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        // 绑定队列到交换机
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "item.#");
        // 同一时刻服务器只会发一条消息给消费者
        channel.basicQos(1);
        // 定义队列的消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 监听队列,手动返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);
        // 获取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" 搜索系统: '" + message + "'");
            Thread.sleep(10);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

        消费者端的的队列在绑定交换机时只需要写item.#即可匹配到item.delete和item.update。

小结

        本篇文章中的三种消息队列包含的元素相同,功能是越来越灵活的,之所以能实现这种效果,是因为交换机有不同的模式,三种模式的生产者端在声明交换机时分别使用了不同的模式。

        订阅模式——Fanout

        路由模式——Direct
        通配模式——Topic
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值