当前位置:首页 > 科技  > 软件

RabbitMQ工作模式-Publish/Subscribe发布与订阅模式

来源: 责编: 时间:2023-11-10 17:08:11 434观看
导读订阅模式类型订阅模式示例图:前面2个案例中,只有3个角色:P:生产者,也就是要发送消息的程序C:消费者:消息的接受者,会一直等待消息到来。queue:消息队列,图中红色部分而在订阅模型中,多了一个exchange角色,而且过程略有变化:P:生产者

agu28资讯网——每日最新资讯28at.com

订阅模式类型

订阅模式示例图:agu28资讯网——每日最新资讯28at.com

agu28资讯网——每日最新资讯28at.com

前面2个案例中,只有3个角色:agu28资讯网——每日最新资讯28at.com

  • P:生产者,也就是要发送消息的程序
  • C:消费者:消息的接受者,会一直等待消息到来。
  • queue:消息队列,图中红色部分

而在订阅模型中,多了一个exchange角色,而且过程略有变化:agu28资讯网——每日最新资讯28at.com

  • P:生产者,也就是要发送消息的程序,但是不再发送到队列中,而是发给X(交换机)
  • C:消费者,消息的接受者,会一直等待消息到来。
  • Queue:消息队列,接收消息、缓存消息。
  • Exchange:交换机,图中的X。一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有常见以下3种类型:
  • Fanout:广播,将消息交给所有绑定到交换机的队列
  • Direct:定向,把消息交给符合指定routing key 的队列
  • Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列

Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!agu28资讯网——每日最新资讯28at.com

Publish/Subscribe发布与订阅模式

1、模式说明

agu28资讯网——每日最新资讯28at.com

发布订阅模式:agu28资讯网——每日最新资讯28at.com

每个消费者监听自己的队列。agu28资讯网——每日最新资讯28at.com

生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收 到消息agu28资讯网——每日最新资讯28at.com

2、案例

(1)生产者

agu28资讯网——每日最新资讯28at.com

package com.lijw.producer;import com.rabbitmq.client.BuiltinExchangeType;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 Aron.li * @date 2022/3/3 8:16 */public class Producer_PubSub {    public static void main(String[] args) throws IOException, TimeoutException {        //1.创建连接工厂        ConnectionFactory factory = new ConnectionFactory();        //2. 设置参数        factory.setHost("127.0.0.1"); // ip  默认值 localhost        factory.setPort(5672); //端口  默认值 5672        factory.setVirtualHost("/test"); //虚拟机 默认值 /        factory.setUsername("libai"); // 用户名 默认 guest        factory.setPassword("libai"); //密码 默认值 guest        //3. 创建连接 Connection        Connection connection = factory.newConnection();        //4. 创建Channel        Channel channel = connection.createChannel();        //5. 创建交换机        /*           exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)           参数:            1. exchange:交换机名称            2. type:交换机类型                DIRECT("direct"):定向                FANOUT("fanout"):扇形(广播),发送消息到每一个与之绑定队列。                TOPIC("topic") 通配符的方式                HEADERS("headers") 参数匹配            3. durable:是否持久化            4. autoDelete:自动删除            5. internal:内部使用。 一般false            6. arguments:参数        */        String exchangeName = "test_fanout";        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT, true, false, false, null);        //6. 创建队列        String queue1Name = "test_fanout_queue1";        String queue2Name = "test_fanout_queue2";        channel.queueDeclare(queue1Name, true, false, false, null);        channel.queueDeclare(queue2Name, true, false, false, null);        // 7. 绑定队列和交换机        /*            queueBind(String queue, String exchange, String routingKey)            参数:                1. queue:队列名称                2. exchange:交换机名称                3. routingKey:路由键,绑定规则                    如果交换机的类型为fanout ,routingKey设置为""         */        channel.queueBind(queue1Name, exchangeName, "");        channel.queueBind(queue2Name, exchangeName, "");        //8. 发送消息至交换机,由交换机分发消息        String body = "日志信息: 肥仔白调用了findAll方法...日志级别: INFO....";        channel.basicPublish(exchangeName, "", null, body.getBytes());        //9. 释放资源        channel.close();        connection.close();            }}

执行生产者,我们可以查看一下创建的 交换机 以及 队列信息:agu28资讯网——每日最新资讯28at.com

agu28资讯网——每日最新资讯28at.com

agu28资讯网——每日最新资讯28at.com

下面再来看看队列,如下:agu28资讯网——每日最新资讯28at.com

agu28资讯网——每日最新资讯28at.com

agu28资讯网——每日最新资讯28at.com

下面我们继续来写两个消费者接收消息。agu28资讯网——每日最新资讯28at.com

(2)消费者1:读取队列1的消息

agu28资讯网——每日最新资讯28at.com

package com.lijw.consumer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.concurrent.TimeoutException;/** * @author Aron.li * @date 2022/3/2 16:16 */public class Consumer_PubSub1 {    //定义接收队列的名称    final static String queueName = "test_fanout_queue1";    public static void main(String[] args) throws IOException, TimeoutException {        //1.创建连接工厂        ConnectionFactory factory = new ConnectionFactory();        //2. 设置参数        factory.setHost("127.0.0.1"); // ip  默认值 localhost        factory.setPort(5672); //端口  默认值 5672        factory.setVirtualHost("/test"); //虚拟机 默认值 /        factory.setUsername("libai"); // 用户名 默认 guest        factory.setPassword("libai"); //密码 默认值 guest        //3. 创建连接 Connection        Connection connection = factory.newConnection();        //4. 创建Channel        Channel channel = connection.createChannel();        //5. 创建队列Queue        /*        queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)        参数:            1. queue:队列名称            2. durable:是否持久化,当mq重启之后,还在            3. exclusive:                * 是否独占。只能有一个消费者监听这队列                * 当Connection关闭时,是否删除队列            4. autoDelete:是否自动删除。当没有Consumer时,自动删除掉            5. arguments:参数。         */        channel.queueDeclare(queueName, true, false, false, null);        /*        basicConsume(String queue, boolean autoAck, Consumer callback)        参数:            1. queue:队列名称            2. autoAck:是否自动确认            3. callback:回调对象         */        // 接收消息        Consumer consumer = new DefaultConsumer(channel){            /*                回调方法,当收到消息后,会自动执行该方法                1. consumerTag:标识                2. envelope:获取一些信息,交换机,路由key...                3. properties:配置信息                4. body:数据             */            @Override            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                System.out.println("接收队列的数据 body: " + new String(body));            }        };        channel.basicConsume(queueName,true,consumer);        //不需要关闭资源,因为消费者需要持续监听队列信息    }}

(3)消费者2:读取队列2的消息

agu28资讯网——每日最新资讯28at.com

package com.lijw.consumer;import com.rabbitmq.client.*;import java.io.IOException;import java.util.concurrent.TimeoutException;/** * @author Aron.li * @date 2022/3/2 16:16 */public class Consumer_PubSub2 {    //定义接收队列的名称    final static String queueName = "test_fanout_queue2";    public static void main(String[] args) throws IOException, TimeoutException {        //1.创建连接工厂        ConnectionFactory factory = new ConnectionFactory();        //2. 设置参数        factory.setHost("127.0.0.1"); // ip  默认值 localhost        factory.setPort(5672); //端口  默认值 5672        factory.setVirtualHost("/test"); //虚拟机 默认值 /        factory.setUsername("libai"); // 用户名 默认 guest        factory.setPassword("libai"); //密码 默认值 guest        //3. 创建连接 Connection        Connection connection = factory.newConnection();        //4. 创建Channel        Channel channel = connection.createChannel();        //5. 创建队列Queue        /*        queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)        参数:            1. queue:队列名称            2. durable:是否持久化,当mq重启之后,还在            3. exclusive:                * 是否独占。只能有一个消费者监听这队列                * 当Connection关闭时,是否删除队列            4. autoDelete:是否自动删除。当没有Consumer时,自动删除掉            5. arguments:参数。         */        channel.queueDeclare(queueName, true, false, false, null);        /*        basicConsume(String queue, boolean autoAck, Consumer callback)        参数:            1. queue:队列名称            2. autoAck:是否自动确认            3. callback:回调对象         */        // 接收消息        Consumer consumer = new DefaultConsumer(channel){            /*                回调方法,当收到消息后,会自动执行该方法                1. consumerTag:标识                2. envelope:获取一些信息,交换机,路由key...                3. properties:配置信息                4. body:数据             */            @Override            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {                System.out.println("接收队列的数据 body: " + new String(body));            }        };        channel.basicConsume(queueName,true,consumer);        //不需要关闭资源,因为消费者需要持续监听队列信息    }}

3、测试

启动所有消费者,然后使用生产者发送消息;在每个消费者对应的控制台可以查看到生产者发送的所有消息;到达广播的效果。agu28资讯网——每日最新资讯28at.com

  • 消费者1接收到的消息:

agu28资讯网——每日最新资讯28at.com

  • 消费者2接收到的消息:

agu28资讯网——每日最新资讯28at.com

从结果来看,生产者只需要发送一条消息,其余的消费者全部收到了消息,达到了广播的效果。agu28资讯网——每日最新资讯28at.com

4、小结

交换机需要与队列进行绑定,绑定之后;一个消息可以被多个消费者都收到。agu28资讯网——每日最新资讯28at.com

发布订阅模式与工作队列模式的区别:agu28资讯网——每日最新资讯28at.com

  • 工作队列模式不用定义交换机,而发布/订阅模式需要定义交换机。
  • 发布/订阅模式的生产方是面向交换机发送消息,工作队列模式的生产方是面向队列发送消息(底层使用默认交换机)。
  • 发布/订阅模式需要设置队列和交换机的绑定,工作队列模式不需要设置,实际上工作队列模式会将队列绑 定到默认的交换机 。

本文链接:http://www.28at.com/showinfo-26-20057-0.htmlRabbitMQ工作模式-Publish/Subscribe发布与订阅模式

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Oracle数据库调优实战:优化SQL查询的黄金法则!

下一篇: 学会使用Java的远程调试工具,解决难题

标签:
  • 热门焦点
  • 天猫精灵Sound Pro体验:智能音箱没有音质?来听听我的

    这几年除了手机作为智能生活终端最主要的核心之外,第二个可以成为中心点的产品是什么?——是智能音箱。 手机在执行命令的时候有两种操作方式,手和智能语音助手,而智能音箱只
  • 服务存储设计模式:Cache-Aside模式

    Cache-Aside模式一种常用的缓存方式,通常是把数据从主存储加载到KV缓存中,加速后续的访问。在存在重复度的场景,Cache-Aside可以提升服务性能,降低底层存储的压力,缺点是缓存和底
  • 如何使用JavaScript创建一只图像放大镜?

    译者 | 布加迪审校 | 重楼如果您曾经浏览过购物网站,可能遇到过图像放大功能。它可以让您放大图像的特定区域,以便浏览。结合这个小小的重要功能可以大大改善您网站的用户体验
  • Temu起诉SHEIN,跨境电商战事升级

    来源 | 伯虎财经(bohuFN)作者 | 陈平安日前据外媒报道,拼多多旗下跨境电商平台Temu正对竞争对手SHEIN提起新诉讼,诉状称Shein&ldquo;利用市场支配力量强迫服装厂商与之签订独家
  • 年轻人的“职场羞耻感”,无处不在

    作者:冯晓亭 陶 淘 李 欣 张 琳 马舒叶来源:燃次元&ldquo;人在职场,应该选择什么样的着装?&rdquo;近日,在网络上,一个与着装相关的帖子引发关注,在该帖子里,一位在高级写字楼亚洲金
  • 重估百度丨大模型,能撑起百度的“今天”吗?

    自象限原创 作者|程心 罗辑2023年之前,对于自己的&ldquo;今天&rdquo;,百度也很迷茫。&ldquo;新业务到 2022 年底还是 0,希望 2023 年出来一个 1。&rdquo;这是2022年底,李彦宏
  • 消息称小米汽车开始筛选交付中心:需至少120个车位

    IT之家 7 月 7 日消息,日前,有微博简介为“汽车行业从业者、长三角一体化拥护者”的微博用户 @长三角行健者 发文表示,据经销商集团反馈,小米汽车目前
  • 联想的ThinkBook Plus下一版曝光,键盘旁边塞个平板

    ThinkBook Plus 是联想的一个特殊笔记本类别,它在封面放入了一块墨水屏,也给人留下了较为深刻的印象。据有人爆料,联想的下一款 ThinkBook Plus 可能更特殊,它
  • 上海举办人工智能大会活动,建设人工智能新高地

    人工智能大会在上海浦江两岸隆重拉开帷幕,人工智能新技术、新产品、新应用、新理念集中亮相。8月30日晚,作为大会的特色活动之一的上海人工智能发展盛典人工
Top