前两章我们讲了RabbitMQ的direct模式和fanout模式,本章介绍topic主题模式的应用。如果对direct模式下通过routingkey来匹配消息的模式已经有一定了解那fanout也很好理解。简单的可以理解成direct是通过routingkey精准匹配的,而topic是通过routingkey来模糊匹配。 
在topic模式下支持两个特殊字符的匹配。

* (星号) 代表任意 一个单词
# (井号) 0个或者多个单词

注意:上面说的是单词不是字符。

如下图所示,RabbitMQ direct模式通过RoutingKey来精准匹配,RoutingKey为red的投递到Queue1,RoutingKey为black和white的投递到Queue2。

我们可以假设一个场景,我们要做一个日志模块来收集处理不同的日志,日志区分包含三个维度的标准:模块、日志紧急程度、日志重要程度。模块分为:red、black、white;紧急程度分为:critical、normal;把重要程度分为:medium、low、high在RoutingKey字段中我们把这三个维度通过两个“.“连接起来。 
现在我们需要对black模块,紧急程度为critical,重要程度为high的日志分配到队列1打印到屏幕;对所以模块重要程度为high的日志和white紧急程度为critical的日志发送到队列2持久化到硬盘。如下示例:

  • RoutingKey为“black.critical.high”的日志会投递到queue1和queue2,。

  • RoutingKey为“red.critical.high”的日志会只投递到queue2。

  • RoutingKey为“white.critical.high”的日志会投递到queue2,并且虽然queue2的两个匹配规则都符合但只会向queue2投递一份。

新建TopicProduct用来发布三种routingkey的消息。

using System;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events; namespace TopicProduct
{
class Program
{
static void Main(string[] args)
{
String exchangeName = "wytExchangeTopic";
String routeKeyName1 = "black.critical.high";
String routeKeyName2 = "red.critical.high";
String routeKeyName3 = "white.critical.high"; String message1 = "black-critical-high!";
String message2 = "red-critical-high!";
String message3 = "white-critical-high!"; ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "192.168.63.129";
factory.Port = ;
factory.VirtualHost = "/wyt";
factory.UserName = "wyt";
factory.Password = "wyt"; using (IConnection connection=factory.CreateConnection())
{
using (IModel channel=connection.CreateModel())
{
channel.ExchangeDeclare(exchange: exchangeName, type: "topic", durable: true, autoDelete: false, arguments: null); IBasicProperties properties = channel.CreateBasicProperties();
properties.Persistent = true; Byte[] body1 = Encoding.UTF8.GetBytes(message1);
Byte[] body2 = Encoding.UTF8.GetBytes(message2);
Byte[] body3 = Encoding.UTF8.GetBytes(message3); //消息推送
channel.BasicPublish(exchange: exchangeName, routingKey:routeKeyName1,basicProperties: properties, body: body1);
channel.BasicPublish(exchange: exchangeName, routingKey: routeKeyName2, basicProperties: properties, body: body2);
channel.BasicPublish(exchange: exchangeName, routingKey: routeKeyName3, basicProperties: properties, body: body3); Console.WriteLine(" [x] Sent {0}", message1);
Console.WriteLine(" [x] Sent {0}", message2);
Console.WriteLine(" [x] Sent {0}", message3);
}
} Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}

新建TopicCustomerA接收一种消息

using System;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events; namespace TopicCustomerA
{
class Program
{
static void Main(string[] args)
{
String exchangeName = "wytExchangeTopic";
String routeKeyName1 = "black.critical.high"; ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "192.168.63.129";
factory.Port = ;
factory.VirtualHost = "/wyt";
factory.UserName = "wyt";
factory.Password = "wyt"; using (IConnection connection=factory.CreateConnection())
{
using (IModel channel=connection.CreateModel())
{
channel.ExchangeDeclare(exchange: exchangeName, type: "topic", durable: true, autoDelete: false, arguments: null); String queueName = channel.QueueDeclare().QueueName; channel.QueueBind(queue: queueName, exchange: exchangeName, routingKey: routeKeyName1, arguments: null); EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
var routingKey = ea.RoutingKey;
Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message); channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
}; channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer); Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}
}
}

新建TopicCustomerB接收两种消息

using System;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events; namespace TopicCustomerB
{
class Program
{
static void Main(string[] args)
{
String exchangeName = "wytExchangeTopic";
String routeKeyName1 = "red.critical.*";
String routeKeyName2 = "white.critical.*"; ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "192.168.63.129";
factory.Port = ;
factory.VirtualHost = "/wyt";
factory.UserName = "wyt";
factory.Password = "wyt"; using (IConnection connection = factory.CreateConnection())
{
using (IModel channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchange: exchangeName, type: "topic", durable: true, autoDelete: false, arguments: null); String queueName = channel.QueueDeclare().QueueName; channel.QueueBind(queue: queueName, exchange: exchangeName, routingKey: routeKeyName1, arguments: null);
channel.QueueBind(queue: queueName, exchange: exchangeName, routingKey: routeKeyName2, arguments: null); EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
var routingKey = ea.RoutingKey;
Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message); channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
}; channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer); Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}
}
}

先运行TopicCustomerA和TopicCustomerB保持订阅状态。然后执行TopicProduct发布消息。TopicCustomerA和TopicCustomerB收到的消息如下:

如上截图,验证了我们之前的结论。

另外还有一些特殊情况例如:

如果binding_key 是 “#” - 它会接收所有的Message,不管routing_key是什么,就像是fanout
exchange。
如果 “*” and “#” 没有被使用,那么topic exchange就变成了direct exchange。

RabbitMQ消息队列(八)-通过Topic主题模式分发消息(.Net Core版)的更多相关文章

  1. (八)RabbitMQ消息队列-通过Topic主题模式分发消息

    原文:(八)RabbitMQ消息队列-通过Topic主题模式分发消息 前两章我们讲了RabbitMQ的direct模式和fanout模式,本章介绍topic主题模式的应用.如果对direct模式下通过 ...

  2. Spring Boot 之 RabbitMQ 消息队列中间件的三种模式

    开门见山(文末附有消息队列的几个基本概念) 1.直接模式( Direct)模式 直白的说就是一对一,生产者对应唯一的消费者(当然同一个消费者可以开启多个服务). 虽然使用了自带的交换器(Exchang ...

  3. (九)RabbitMQ消息队列-通过Headers模式分发消息

    原文:(九)RabbitMQ消息队列-通过Headers模式分发消息 Headers类型的exchange使用的比较少,以至于官方文档貌似都没提到,它是忽略routingKey的一种路由方式.是使用H ...

  4. RabbitMQ入门教程(十七):消息队列的应用场景和常见的消息队列之间的比较

    原文:RabbitMQ入门教程(十七):消息队列的应用场景和常见的消息队列之间的比较 分享一个朋友的人工智能教程.比较通俗易懂,风趣幽默,感兴趣的朋友可以去看看. 这是网上的一篇教程写的很好,不知原作 ...

  5. (转)RabbitMQ消息队列(九):Publisher的消息确认机制

    在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...

  6. RabbitMQ消息队列(九):Publisher的消息确认机制

    在前面的文章中提到了queue和consumer之间的消息确认机制:通过设置ack.那么Publisher能不到知道他post的Message有没有到达queue,甚至更近一步,是否被某个Consum ...

  7. (五)RabbitMQ消息队列-安装amqp扩展并订阅/发布Demo(PHP版)

    原文:(五)RabbitMQ消息队列-安装amqp扩展并订阅/发布Demo(PHP版) 本文将介绍在PHP中如何使用RabbitMQ来实现消息的订阅和发布.我使用的系统依然是Centos7,为了方便, ...

  8. RabbitMQ消息队列(七)-通过fanout模式将消息推送到多个Queue中(.Net Core版)

    前面第六章我们使用的是direct直连模式来进行消息投递和分发.本章将介绍如何使用fanout模式将消息推送到多个队列. 有时我们会遇到这样的情况,多个功能模块都希望得到完整的消息数据.例如一个log ...

  9. Rabbitmq消息队列(六) 主题交换机

    1.简介 前面学习了有选择性的接收消息,但是却没有办法基于多个标准来接收消息.为了实现这个目的,接下来我们学习如何使用另一种更复杂的交换机 —— 主题交换机. 2.主题交换机 发送到主题交换机(top ...

随机推荐

  1. 分布式、集群、微服务、SOA 之间的区别

    分布式:不同模块部署在不同服务器上 作用:分布式解决网站高并发带来问题 集群:多台服务器部署相同应用构成一个集群 作用:通过负载均衡设备共同对外提供服务 SOA:Service Oriented Ar ...

  2. 你不知道的JS之作用域和闭包(三)函数 vs. 块级作用域

      原文:你不知道的js系列 在第(二)节中提到的,标识符在作用域中声明,这些作用域就像是一个容器,一个嵌套一个,这个嵌套关系是在代码编写时定义的. 那么到底是什么产生了一个新的作用域,只有函数能做到 ...

  3. Java和js操作json

    Js中 Json字符串转json对象 //将json格式的字符串转为json对象 var t = JSON.parse('{"name":123}'); alert(t.name) ...

  4. Restful levels&HATEOAS

    RESTful: Rest是一种软件架构风格.设计风格,而不是标准,只是提供了一组设计原则和约束条件.它主要用于客户端和服务器交互类的软件.基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等 ...

  5. SDKmanager的位置

    最近学习Android Studio 因为配置的问题,需要查找SDKmanager的位置 一下是查找方法: 查找到啦~

  6. Swift 编程杂谈

    1.Swift 3.0 使用Cocopods 导入第三方报错 之前一直用Object-C 编写代码  用Cocopods导入第三方没出过什么问题(PS:2017最新cocoaPods安装教程) 今天用 ...

  7. windows 10 64位机器上 安装部署

    mi这个博客写的不错 https://www.cnblogs.com/dingguofeng/p/8709476.html 安装redis 可视化工具后 ,新建连接 名称随意,注意端口号是否有误默认6 ...

  8. python—迭代器、生成器

    1.迭代器(iteration) 迭代器协议:提供next()方法,该方法要么返回迭代的下一项,要么异常.(只能往后走) 可迭代对象:实现迭代器协议的对象. **字符串.列表.元祖.字典.集合.文件都 ...

  9. Xaml Controls Gallery 的五个没有用的控件

    HyperlinkButton 功能:这个控件可以实现点击按钮后跳到另一个按钮的功能. 我觉得这个功能有些多余,据我了解,一些深受欢迎的游戏大都具备的一个特点,那就是操作简单,界面中不会出现冗余的东西 ...

  10. 回顾4180天在腾讯使用C#的历程,开启新的征途

    今天是2018年8月8日,已经和腾讯解除劳动关系,我的公司正式开始运营,虽然还有很多事情需要理清,公司官网也没有做,接下来什么事情都需要自己去完成了,需要一步一个脚印去完善,开启一个新的征途,我将在博 ...