发布与订阅

在我们使用手机发送消息的时候,即可以选择给单个手机号码发送消息,也可以选择多个手机号码,群发消息。

前面学习工作队列的时候,我们使用的场景是一个消息只能被一个消费者程序实例接收并处理,但是如果想要群发消息,仅凭之前学到的东西是实现不了的。

所以这里需要引入RabbitMQ的发布与订阅模式。

Exchange

什么是Exchange?

RabbitMQ通信模型的核心思想是消息生产者不会直接发送消息到消息队列,生产者程序也不知道他产生的消息是否发送到了一个消息队列中。

实际上消息生产者只会发送消息到一个Exchange对象。Exchange是英语中交换的意思,这RabbitMQ中它实际就是一个消息的中转站,一方面它会接收所有与它绑定的生产者程序实例产生的消息,一方面它有会根据自身的定义将消息发送到不同的消息队列中。不同的Exchange类型决定了它会将消息发送到一个特定的消息队列,还是多个消息队列。

Exchange有四种类型

  • direct
  • topic
  • headers
  • fanout

RabbitMQ的发布和订阅模式会使用fanout类型的Exchange。

“fanout”在英语中是扇出、展开的意思,这种类型的Exchange会将收到的一条消息,发送到多个消息队列中,而不同的消息消费者实例监听不同的消息队列,从而实现消息广播的功能。

如何设置Exchange

我们可以使用channel对象中的ExchangeDeclare方法来声明Exchange

channel.ExchangeDeclare("logs", "fanout");

这个方法的第一个参数是Exchange的名称,第二个参数是Exchange的类型。

当我们调用channel对象的BasicPublish方法发送消息的时候,我们可以设置Exchange参数

public static void BasicPublish(this IModel model, string exchange, string routingKey, IBasicProperties basicProperties, byte[] body);

例:

channel.BasicPublish(exchange: "logs",

                     routingKey: "",

                     basicProperties: null,

                     body: body);

默认Exchange

回想上一章工作队列的例子,会发现之前才发布消息的时候,我们有传递一个空 exchange

channel.BasicPublish(exchange: "",

                        routingKey: "work_queue",

                        basicProperties: properties,

                        body: body

                    );

那为什么消息会正确的发送到消息消费者程序实例呢?

这个其实是RabbitMQ的一个默认设置,当发送消息时,如果将exchange设置为空字符串,系统会自动启用一个默认的Exchange, 这个Exchange会把消息自动添加到第二个参数routeingKey指定的消息队列中(在上一章的例子中,即work_queue消息队列),所以消息消费者程序实例才能正确的接收消息。

临时消息队列

当我们群发消息的时候,我们需要为每个消息消费者实例创建一个名字独特的消息队列。

但是这里我们只是关注群发消息,而不想去关注为消息队列起名字这件事情。

RabbitMQ提供了一种临时消息队列,来帮助我们简化这个操作。

当我们在声明消息队列的时候,不传递任何参数,生成的就是一个临时消息队列

channel.QueueDeclare();

而如果想获得这个消息队列的名字,我们可以从它的QueueName属性中获取。

var queueName = channel.QueueDeclare().QueueName;

这个queueName是RabbitMQ帮我们动态随机生成,例:amq.gen-JzTY20BRgKO-HjmUJj0wLg.

Exchange和消息队列绑定

当我们创建了一个 Exchange之后,我们需要设置Exchange给那些消息队列发送消息,Exchange和消息队列之间的关系叫做Binding(绑定)

在channel对象中有一个QueueBind的方法来帮助我们完成这一操作

channel.QueueBind(queue: queueName,

                  exchange: "logs",

                  routingKey: "");

修改程序

现在我们修改一下我们之前的发送消息程序,将它改造成一个消息群发器。

Send

  1. 声明一个名为broadcast的Exchange
  2. 修改发送消息部分的代码,现在直接发送到创建的Exchange中
static void Main(string[] args)

        {

            var factory = new ConnectionFactory()

            {

                HostName = "localhost"

            };

 

            using (var connection = factory.CreateConnection())

            {

                using (var channel = connection.CreateModel())

                {

                    channel.ExchangeDeclare("broadcast", "fanout");

 

                    string message = args[0];

                    var body = Encoding.UTF8.GetBytes(message);

 

                    channel.BasicPublish(exchange: "broadcast",

                        routingKey: "",

                        basicProperties: null,

                        body: body

                    );

 

                    Console.WriteLine("[x] Sent {0}", message);

                }

            }

        }

Receive

  1. 使用临时消息队列
  2. 将Exchange和临时消息队列绑定
static void Main(string[] args)

        {

            var factory = new ConnectionFactory() { HostName = "localhost" };

 

            using (var connection = factory.CreateConnection())

            {

                using (var channel = connection.CreateModel())

                {

                    channel.ExchangeDeclare("broadcast", "fanout");

 

                    var queueName = channel.QueueDeclare().QueueName;

 

                    channel.QueueBind(queue: queueName, exchange: "broadcast", routingKey: "");

 

                    var consumer = new EventingBasicConsumer(channel);

 

                    consumer.Received += (model, ea) =>

                    {

                        var body = ea.Body;

                        var message = Encoding.UTF8.GetString(body);

                        Console.WriteLine("[x] Received {0}", message);

                    };

 

                    channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);

 

                    Console.Read();

                }

            }

        }

最终效果

我们启动1个Send程序,2个Receive程序。

RabbitMQ学习笔记(三) 发布与订阅的更多相关文章

  1. StackExchange.Redis学习笔记(五) 发布和订阅

    Redis命令中的Pub/Sub Redis在 2.0之后的版本中 实现了 事件推送的  发布订阅命令 以下是Redis关于发布和订阅提供的相关命令 SUBSCRIBE channel [channe ...

  2. rabbitMQ学习笔记(四) 发布/订阅消息

    前面都是一条消息只会被一个消费者处理. 如果要每个消费者都处理同一个消息,rabbitMq也提供了相应的方法. 在以前的程序中,不管是生产者端还是消费者端都必须知道一个指定的QueueName才能发送 ...

  3. jw player学习笔记三---发布到其它网站

    一.通过官网发布向导 登陆 http://www.longtailvideo.com,注册一个账号,进入你的用户管理中心,如下图 然后按提示,一步步操作,就会得到js代码了. 二.自己服务器发布 &l ...

  4. rabbitMQ学习笔记(三) 消息确认与公平调度消费者

    从本节开始称Sender为生产者 , Recv为消费者   一.消息确认 为了确保消息一定被消费者处理,rabbitMQ提供了消息确认功能,就是在消费者处理完任务之后,就给服务器一个回馈,服务器就会将 ...

  5. RabbitMQ学习笔记三:Java实现RabbitMQ之与Spring集成

    搭建好maven项目环境,加入RabbitMQ依赖包 <dependency> <groupId>org.springframework.amqp</groupId> ...

  6. RabbitMQ学习笔记五:RabbitMQ之优先级消息队列

    RabbitMQ优先级队列注意点: 1.只有当消费者不足,不能及时进行消费的情况下,优先级队列才会生效 2.RabbitMQ3.5以后才支持优先级队列 代码在博客:RabbitMQ学习笔记三:Java ...

  7. 官网英文版学习——RabbitMQ学习笔记(一)认识RabbitMQ

    鉴于目前中文的RabbitMQ教程很缺,本博主虽然买了一本rabbitMQ的书,遗憾的是该书的代码用的不是java语言,看起来也有些不爽,且网友们不同人学习所写不同,本博主看的有些地方不太理想,为此本 ...

  8. RabbitMQ学习笔记(五) Topic

    更多的问题 Direct Exchange帮助我们解决了分类发布与订阅消息的问题,但是Direct Exchange的问题是,它所使用的routingKey是一个简单字符串,这决定了它只能按照一个条件 ...

  9. Part1.2 、RabbitMQ -- Publish/Subscribe 【发布和订阅】

    python 目录 (一).交换 (Exchanges) -- 1.1 武sir 经典 Exchanges 案例展示. (二).临时队列( Temporary queues ) (三).绑定(Bind ...

  10. RabbitMQ学习系列三-C#代码接收处理消息

    RabbitMQ学习系列三:.net 环境下 C#代码订阅 RabbitMQ 消息并处理 http://www.80iter.com/blog/1438251320680361 http://www. ...

随机推荐

  1. hashMap源码学习记录

    hashMap作为java开发面试最常考的一个题目之一,有必要花时间去阅读源码,了解底层实现原理. 首先,让我们看看hashMap这个类有哪些属性 // hashMap初始数组容量 static fi ...

  2. SpringBoot配置文件

    一.配置文件 配置文件应该是无论在哪个框架中都是一个重要角色,而我们最为常用的xxx.xml和xxx.properties,还有springboot推荐使用的xxx.yml. 二.SpringBoot ...

  3. ElasticSearch本人启动报错总结

    1.报错关键代码如下: Exception in thread "main" 2019-04-28 03:53:04,339 main ERROR No log4j2 config ...

  4. Alpha冲刺(5/10)——2019.4.27

    作业描述 课程 软件工程1916|W(福州大学) 团队名称 修!咻咻! 作业要求 项目Alpha冲刺(团队) 团队目标 切实可行的计算机协会维修预约平台 开发工具 Eclipse 团队信息 队员学号 ...

  5. c++ 积累

    class MyClass { public: MyClass()=default; MyClass(const MyClass& )=delete; ...... 有些时候我们希望限制默认函 ...

  6. Sublime Text3 & MinGW & LLVM CLang 安装配置C-C++编译环境

    Sublime Text是一款强大的跨平台代码编辑器,小巧而且丰富实用的功能是Visual Studio不能比拟的,但是编译运行是一个软肋,本文通过在sublime中配置g++编译器实现程序的编译功能 ...

  7. Oracle在.sql文件中创建存储过程

    创建存储过程的语法网上到处都有. 可我执行了半天都创建不成功. 最后,发现! 在最后加个 / 就可以了!!! 真坑啊 今天连续被Oracle坑了两次了. 最后,感谢这个人https://blog.cs ...

  8. Vue 入门. 如何在HTML代码里面快速使用Vue

    概述 browserify是一个 CommonJS风格的模块管理和打包工具,上一篇我们简单地介绍了Vue.js官方基于browserify构筑的一套开发模板.webpack提供了和browserify ...

  9. tomcat安装启动startup.bat文件命令行界面出现乱码的问题解决

    进入tomcat安装界面,进入conf文件夹,找打logging.properties,打开进行编辑,在最后添加一句 java.util.logging.ConsoleHandler.encoding ...

  10. vue项目中引入mint-ui的方式(全部引入与按需引入)

    参考哦 https://blog.csdn.net/qq_36742720/article/details/83620584 https://jingyan.baidu.com/article/c1a ...