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

  1. * (星号) 代表任意 一个单词
  2. # (井号) 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的消息。

  1. using System;
  2. using System.Text;
  3. using RabbitMQ.Client;
  4. using RabbitMQ.Client.Events;
  5.  
  6. namespace TopicProduct
  7. {
  8. class Program
  9. {
  10. static void Main(string[] args)
  11. {
  12. String exchangeName = "wytExchangeTopic";
  13. String routeKeyName1 = "black.critical.high";
  14. String routeKeyName2 = "red.critical.high";
  15. String routeKeyName3 = "white.critical.high";
  16.  
  17. String message1 = "black-critical-high!";
  18. String message2 = "red-critical-high!";
  19. String message3 = "white-critical-high!";
  20.  
  21. ConnectionFactory factory = new ConnectionFactory();
  22. factory.HostName = "192.168.63.129";
  23. factory.Port = ;
  24. factory.VirtualHost = "/wyt";
  25. factory.UserName = "wyt";
  26. factory.Password = "wyt";
  27.  
  28. using (IConnection connection=factory.CreateConnection())
  29. {
  30. using (IModel channel=connection.CreateModel())
  31. {
  32. channel.ExchangeDeclare(exchange: exchangeName, type: "topic", durable: true, autoDelete: false, arguments: null);
  33.  
  34. IBasicProperties properties = channel.CreateBasicProperties();
  35. properties.Persistent = true;
  36.  
  37. Byte[] body1 = Encoding.UTF8.GetBytes(message1);
  38. Byte[] body2 = Encoding.UTF8.GetBytes(message2);
  39. Byte[] body3 = Encoding.UTF8.GetBytes(message3);
  40.  
  41. //消息推送
  42. channel.BasicPublish(exchange: exchangeName, routingKey:routeKeyName1,basicProperties: properties, body: body1);
  43. channel.BasicPublish(exchange: exchangeName, routingKey: routeKeyName2, basicProperties: properties, body: body2);
  44. channel.BasicPublish(exchange: exchangeName, routingKey: routeKeyName3, basicProperties: properties, body: body3);
  45.  
  46. Console.WriteLine(" [x] Sent {0}", message1);
  47. Console.WriteLine(" [x] Sent {0}", message2);
  48. Console.WriteLine(" [x] Sent {0}", message3);
  49. }
  50. }
  51.  
  52. Console.WriteLine(" Press [enter] to exit.");
  53. Console.ReadLine();
  54. }
  55. }
  56. }

新建TopicCustomerA接收一种消息

  1. using System;
  2. using System.Text;
  3. using RabbitMQ.Client;
  4. using RabbitMQ.Client.Events;
  5.  
  6. namespace TopicCustomerA
  7. {
  8. class Program
  9. {
  10. static void Main(string[] args)
  11. {
  12. String exchangeName = "wytExchangeTopic";
  13. String routeKeyName1 = "black.critical.high";
  14.  
  15. ConnectionFactory factory = new ConnectionFactory();
  16. factory.HostName = "192.168.63.129";
  17. factory.Port = ;
  18. factory.VirtualHost = "/wyt";
  19. factory.UserName = "wyt";
  20. factory.Password = "wyt";
  21.  
  22. using (IConnection connection=factory.CreateConnection())
  23. {
  24. using (IModel channel=connection.CreateModel())
  25. {
  26. channel.ExchangeDeclare(exchange: exchangeName, type: "topic", durable: true, autoDelete: false, arguments: null);
  27.  
  28. String queueName = channel.QueueDeclare().QueueName;
  29.  
  30. channel.QueueBind(queue: queueName, exchange: exchangeName, routingKey: routeKeyName1, arguments: null);
  31.  
  32. EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
  33. consumer.Received += (model, ea) =>
  34. {
  35. var body = ea.Body;
  36. var message = Encoding.UTF8.GetString(body);
  37. var routingKey = ea.RoutingKey;
  38. Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message);
  39.  
  40. channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
  41. };
  42.  
  43. channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer);
  44.  
  45. Console.WriteLine(" Press [enter] to exit.");
  46. Console.ReadLine();
  47. }
  48. }
  49. }
  50. }
  51. }

新建TopicCustomerB接收两种消息

  1. using System;
  2. using System.Text;
  3. using RabbitMQ.Client;
  4. using RabbitMQ.Client.Events;
  5.  
  6. namespace TopicCustomerB
  7. {
  8. class Program
  9. {
  10. static void Main(string[] args)
  11. {
  12. String exchangeName = "wytExchangeTopic";
  13. String routeKeyName1 = "red.critical.*";
  14. String routeKeyName2 = "white.critical.*";
  15.  
  16. ConnectionFactory factory = new ConnectionFactory();
  17. factory.HostName = "192.168.63.129";
  18. factory.Port = ;
  19. factory.VirtualHost = "/wyt";
  20. factory.UserName = "wyt";
  21. factory.Password = "wyt";
  22.  
  23. using (IConnection connection = factory.CreateConnection())
  24. {
  25. using (IModel channel = connection.CreateModel())
  26. {
  27. channel.ExchangeDeclare(exchange: exchangeName, type: "topic", durable: true, autoDelete: false, arguments: null);
  28.  
  29. String queueName = channel.QueueDeclare().QueueName;
  30.  
  31. channel.QueueBind(queue: queueName, exchange: exchangeName, routingKey: routeKeyName1, arguments: null);
  32. channel.QueueBind(queue: queueName, exchange: exchangeName, routingKey: routeKeyName2, arguments: null);
  33.  
  34. EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
  35. consumer.Received += (model, ea) =>
  36. {
  37. var body = ea.Body;
  38. var message = Encoding.UTF8.GetString(body);
  39. var routingKey = ea.RoutingKey;
  40. Console.WriteLine(" [x] Received '{0}':'{1}'", routingKey, message);
  41.  
  42. channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
  43. };
  44.  
  45. channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer);
  46.  
  47. Console.WriteLine(" Press [enter] to exit.");
  48. Console.ReadLine();
  49. }
  50. }
  51. }
  52. }
  53. }

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

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

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

  1. 如果binding_key “#” - 它会接收所有的Message,不管routing_key是什么,就像是fanout
  2. exchange
  3. 如果 “*” 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. 我的 FPGA 学习历程(08)—— 实验:点亮单个数码管

    数码管是一种常见的用于显示的电子器件,根据数码管大致可以分为共阴极和共阳极两种,下图所示的是一个共阳极的数码管的电路图(摘自金沙滩工作室的 51 开发板电路图),我的 AX301 开发板与这张图的情况 ...

  2. Egret的容器--删除对象,遮罩

    class P91F extends egret.Sprite { public constructor() { super(); this.addEventListener(egret.Event. ...

  3. centos docker 升级至最新稳定版--摘自官网

    亲测好使 删除老版本的docker sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ do ...

  4. vue组件之间的传值方式

    一.父组件向子组件传值方式 1.1父组件向子组件传数据方式 <!DOCTYPE html> <html lang="en"> <head> &l ...

  5. Redis配置参数详解

    Redis配置参数详解 /********************************* GENERAL *********************************/ // 是否作为守护进 ...

  6. 了解vue APi

    阳光那么好,何必自寻烦恼,过好每一个当下,一万个美丽的未来抵不过一个温暖的现在. 一.Vue.nextTick(): 该api 是在Dom节点更新结束之后执行的一个延时回调.在修改数据之后,立即使用这 ...

  7. 判断js中的数据类型的几种方法

    判断js中的数据类型有一下几种方法:typeof.instanceof. constructor. prototype. $.type()/jquery.type(),接下来主要比较一下这几种方法的异 ...

  8. html+css手机端自动适应

    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scal ...

  9. mysql5.7忽略大小写问题

    mysql5.7忽略大小写问题 1.1 前言 新安装mysql5.7版本后,linux环境下默认是大小写敏感的. 1.2 忽略大小写敏感步骤 进入mysql配置文件:         vi   /et ...

  10. 格式化数据保留两位小数,输入格式为 :xxx,xx,,,,x,,(x为浮点数)

    /** * 格式化字符串 */ static String dataFormat(String data){ String formatedData = ""; // 浮点数正则表 ...