新的场景

在我们学习了RabbitMQ的发布与订阅之后,我们很容易就可以完成一个简单的消息群发器。

使用这个消息群发器,所有的消费者程序实例都会接收到相同的消息信息,从而实现广播的效果。

但是这种广播是一种无意识的广播,即使消息是有分类的,消费者程序也不能自己决定关注的消息类型,只能被动的接收所有的消息,这就导致消费者程序收到许多无用的消息。

如果想要消费者程序自主决定关注的消息类型,我们可以使用RabbitMQ的Routing机制。

Binding

之前学习RabbitMQ的发布与订阅,我们使用如下代码将消息队列和Exchange进行绑定。

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

其中有一个参数是routingKey, 我们将它设置为空。

对于fanout类型的Exchange, 在绑定消息队列和Exchange的时候,会自动忽略routingKey。

但是Direct类型的Exchange使用这个参数可以帮助我们对消息进行的分类,这里我们可以简单的认为routingKey就是一种消息类型

Direct Exchange

Direct的路由算法很简单,它会将消息发送到与Direct  Exchange绑定并拥有指定routingKey的消息队列中。

一个消息队列与一个Direct Exchange绑定的时候,可以通过多次绑定,拥有多个routingKey。

同理,一个routingKey也可以被多个消息队列拥有。

例:

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

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

在发布与订阅中,我们使用生产者程序向Fanout Exchange发送消息的时候,编写了如下代码

channel.BasicPublish(exchange: "broadcast",

                        routingKey: "",

                        basicProperties: null,

                        body: body

                    );

其中routingKey为空, 因为Fanout Exchange并不关心routingKey。

现在我们使用Direct Exchange, 我们需要指定消息类型routingKey。当Direct Exchnage接收到这条消息之后,它查找和他绑定的所有消息队列,如果消息队列拥有这个routingKey,Direct Exchange就会将这条消息传输给它, 这样监听该消息队列的消费者程序就可以接收到这条消息。

修改代码

Send

  1. Send可以发送3种类型的消息, game, sport, music
  2. 发送消息时必须指定消息的类型
static string[] availableTypes = { "game", "music", "sport" };

 

        static void Main(string[] args)

        {

            if (args == null || args.Length == 0)

            {

                Console.WriteLine("This command line should be like 'dotnet run [message type] [message].'");

                Environment.Exit(1);

            }

 

            var messageType = args[0];

 

            if (!availableTypes.Contains(messageType))

            {

                Console.WriteLine("Available message type can be 'game','music','sport'.");

                Environment.Exit(1);

            }

 

            var factory = new ConnectionFactory()

            {

                HostName = "localhost"

            };

 

            using (var connection = factory.CreateConnection())

            {

                using (var channel = connection.CreateModel())

                {

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

 

                    string message = $"{args[0]} news: {args[1]}";

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

 

                    channel.BasicPublish(exchange: "broadcast",

                        routingKey: messageType,

                        basicProperties: null,

                        body: body

                    );

 

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

                }

            }

        }

Receive

  1. Receive可以接收3种类型的消息, game, sport, music
  2. 程序启动时指定接收的消息类型
static string[] availableTypes = { "game", "music", "sport" };

 

        static void Main(string[] args)

        {

            if (args == null || args.Length == 0)

            {

                Console.WriteLine("This command line should be like 'dotnet run [message type 1] [message type 2] [message type 3].'");

                Environment.Exit(1);

            }

 

            foreach (var type in args)

            {

                if (!availableTypes.Contains(type))

                {

                    Console.WriteLine("Available message type can be 'game','music','sport'.");

                    Environment.Exit(1);

                }

            }

 

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

 

            using (var connection = factory.CreateConnection())

            {

                using (var channel = connection.CreateModel())

                {

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

 

                    var queueName = channel.QueueDeclare().QueueName;

 

                    foreach (var type in args)

                    {

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

                    }

 

                    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。

一个Receive关注game, music类型的消息。

一个Receive关注sport, game类型的消息。

RabbitMQ学习笔记(四) Routing的更多相关文章

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

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

  2. RabbitMQ学习笔记四:RabbitMQ命令(附疑难问题解决)

    本来今天是想做RabbitMQ之优先级队列的,但是,在RabbitMQ Server创建queue时,增加优先级的最大值,头脑发热写了9999999,导致电脑内存直接飙到100%,只能重启电脑,并卸载 ...

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

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

  4. RabbitMQ学习笔记(五) Topic

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

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

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

  6. openresty 学习笔记四:连接mysql和进行相关操作

    openresty 学习笔记四:连接mysql和进行相关操作 毕竟redis是作为缓存,供程序的快速读写,虽然reidis也可以做持久化保存,但还是需要一个做数据存储的数据库.比如首次查询数据在red ...

  7. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  8. IOS学习笔记(四)之UITextField和UITextView控件学习

    IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...

  9. java之jvm学习笔记四(安全管理器)

    java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...

  10. Learning ROS for Robotics Programming Second Edition学习笔记(四) indigo devices

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

随机推荐

  1. Mysql之SQL经验基础积累

    1.根据create_time排序,如何确保null值的排在最前面: 解决办法: ,), a.create_time DESC 结果如下图:

  2. SVM原理 (转载)

    1. 线性分类SVM面临的问题 有时候本来数据的确是可分的,也就是说可以用 线性分类SVM的学习方法来求解,但是却因为混入了异常点,导致不能线性可分,比如下图,本来数据是可以按下面的实线来做超平面分离 ...

  3. notes for python简明学习教程(2)

    方法是只能被该类调用的函数 print函数通常以换行作为输出结尾 字典的items方法 返回的是元组列表 即列表中的每个元素都是元组 切片左闭右开 即开始位置包含在切片中 结束位置不在 每一个对象都能 ...

  4. linux查看空间情况----df与du命令

    1.查看整个磁盘空间使用情况,可以使用命令 :df   -h 2.获取当前的文件夹下的磁盘使用情况,可以使用如下命令:du --max-depth=1 -h 使用 du --max-depth=1 - ...

  5. ECMAScript 6 之 let 和 const 命令

    1.let基本用法 1.1.声明变量 let声明的变量只在它所在的代码块有效. 1.2.不存在变量提升 var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined: let命令 ...

  6. Angular6 用户自定义标签开发

    参考地址:https://www.jianshu.com/p/55e503fd8307

  7. centos7基于samba服务配置实例

    需求: 账号建立:产研部门所有人员,产品.开发.测试.运维: 目录建立:各二级部门分别建立以部门名称为文件夹的目录: 初步权限管理:各部门成员对本部门目录有读写权限,对其他部门目录有读权限: 建立共享 ...

  8. Android像素密度单位解析

    Android应用程序 res/drawable-hdpi drawable-xxhdpi 显示的不同 对比实验: 创建项目后,默认在相关文件目录中生成以下图标: hdpi --> 72px m ...

  9. pip install

    pip install <包名> 或 pip install -r requirements.txt 通过使用 == >= <= > < 来指定版本,不写则安装最新 ...

  10. Makefile自学

    MakeFile的规则 如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接. 如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序. 如果这个工程的头文件被改变了, ...