我们进步改良了我们的日志系统。我们使用direct类型转发器,使得接收者有能力进行选择性的接收日志,,而非fanout那样,只能够无脑的转发。

  虽然使用direct类型改良了我们的系统,但是仍然存在一些局限性:它不能够基于多重条件进行路由选择。
  在我们的日志系统中,我们有可能希望不仅根据日志的级别而且想根据日志的来源进行订阅。这个概念类似unix工具:syslog,它转发日志基于严重性(info/warning/crit…)和设备(auth/cron/kern…)
  这样可能给我们更多的灵活性:我们可能只想订阅来自’cron’的致命错误日志,而不是来自’kern’的。
  为了在我们的系统中实现上述的需求,我们需要学习稍微复杂的主题类型的转发器(topic exchange)。

  1、 主题转发(Topic Exchange)

  发往主题类型的转发器的消息不能随意的设置选择键(routing_key),必须是由点隔开的一系列的标识符组成。标识符可以是任何东西,但是一般都与消息的某些特性相关。一些合法的选择键的例子:"stock.usd.nyse", "nyse.vmw","quick.orange.rabbit".你可以定义任何数量的标识符,上限为255个字节。
  绑定键和选择键的形式一样。主题类型的转发器背后的逻辑和直接类型的转发器很类似:一个附带特殊的选择键将会被转发到绑定键与之匹配的队列中。需要注意的是:关于绑定键有两种特殊的情况。
  *可以匹配一个标识符。
  #可以匹配0个或多个标识符

  2、 图解:

  我们准备发送关于动物的消息。消息会附加一个选择键包含3个标识符(两个点隔开)。第一个标识符描述动物的速度,第二个标识符描述动物的颜色,第三个标识符描述动物的物种:<speed>.<color>.<species>。
  我们创建3个绑定键:Q1与*.orange.*绑定Q2与*.*.rabbit和lazy.#绑定。
  可以简单的认为:
  Q1对所有的橙色动物感兴趣。
  Q2想要知道关于兔子的一切以及关于懒洋洋的动物的一切。
  一个附带quick.orange.rabbit的选择键的消息将会被转发到两个队列。附带lazy.orange.elephant的消息也会被转发到两个队列。另一方面quick.orange.fox只会被转发到Q1,lazy.brown.fox将会被转发到Q2。lazy.pink.rabbit虽然与两个绑定键匹配,但是也只会被转发到Q2一次。quick.brown.fox不能与任何绑定键匹配,所以会被丢弃。
  如果我们违法我们的约定,发送一个或者四个标识符的选择键,类似:orange,quick.orange.male.rabbit,这些选择键不能与任何绑定键匹配,所以消息将会被丢弃。
  另一方面,lazy.orange.male.rabbit,虽然是四个标识符,也可以与lazy.#匹配,从而转发至Q2。
  注:主题类型的转发器非常强大,可以实现其他类型的转发器。
  当一个队列与绑定键#绑定,将会收到所有的消息,类似fanout类型转发器。
  当绑定键中不包含任何#与*时,类似direct类型转发器。

  3、 完整的例子

  发送端

 public class EmitLogTopic
{ private static final String EXCHANGE_NAME = "topic_logs"; public static void main(String[] argv) throws Exception
{
// 创建连接和频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, "topic"); String[] routing_keys = new String[] { "kernal.info", "cron.warning",
"auth.info", "kernel.critical" };
for (String routing_key : routing_keys)
{
String msg = UUID.randomUUID().toString();
channel.basicPublish(EXCHANGE_NAME, routing_key, null, msg
.getBytes());
System.out.println(" [x] Sent routingKey = "+routing_key+" ,msg = " + msg + ".");
} channel.close();
connection.close();
}
}

  接收端1:

 public class ReceiveLogsTopicForKernel
{ private static final String EXCHANGE_NAME = "topic_logs"; public static void main(String[] argv) throws Exception
{
// 创建连接和频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 声明转发器
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
// 随机生成一个队列
String queueName = channel.queueDeclare().getQueue(); //接收所有与kernel相关的消息
channel.queueBind(queueName, EXCHANGE_NAME, "kernel.*"); System.out.println(" [*] Waiting for messages about kernel. To exit press CTRL+C"); QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer); while (true)
{
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
String routingKey = delivery.getEnvelope().getRoutingKey(); System.out.println(" [x] Received routingKey = " + routingKey
+ ",msg = " + message + ".");
}
}
}

  接收端2:

 public class ReceiveLogsTopicForCritical
{ private static final String EXCHANGE_NAME = "topic_logs"; public static void main(String[] argv) throws Exception
{
// 创建连接和频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 声明转发器
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
// 随机生成一个队列
String queueName = channel.queueDeclare().getQueue(); // 接收所有与kernel相关的消息
channel.queueBind(queueName, EXCHANGE_NAME, "*.critical"); System.out
.println(" [*] Waiting for critical messages. To exit press CTRL+C"); QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, consumer); while (true)
{
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
String routingKey = delivery.getEnvelope().getRoutingKey(); System.out.println(" [x] Received routingKey = " + routingKey
+ ",msg = " + message + ".");
}
}
}

  只接收致命错误的日志消息。

  运行结果:

[x] Sent routingKey = kernal.info ,msg = a7261f0d-18cc-4c85-ba80-5ecd9283dae7.
 [x] Sent routingKey = cron.warning ,msg = 0c7e4484-66e0-4846-a869-a7a266e16281.
 [x] Sent routingKey = auth.info ,msg = 3273f21f-6e6e-42f2-83df-1f2fafa7a19a.
 [x] Sent routingKey = kernel.critical ,msg = f65d3e1a-0619-4f85-8b0d-59375380ecc9.

--------------------------------------------------------------------------------------------------------------------

[*] Waiting for messages about kernel. To exit press CTRL+C
 [x] Received routingKey = kernel.critical,msg = f65d3e1a-0619-4f85-8b0d-59375380ecc9.

--------------------------------------------------------------------------------------------------------------------

[*] Waiting for critical messages. To exit press CTRL+C
 [x] Received routingKey = kernel.critical,msg = f65d3e1a-0619-4f85-8b0d-59375380ecc9.

  可以看到,我们通过使用topic类型的转发器,成功实现了多重条件选择的订阅。

参考博客:http://blog.csdn.net/lmj623565791/article/details/37706355

RabbitMQ 主题(Topic)的更多相关文章

  1. (转)RabbitMQ学习之主题topic(java)

    http://blog.csdn.net/zhu_tianwei/article/details/40887775 参考:http://blog.csdn.NET/lmj623565791/artic ...

  2. SpringBoot应用操作Rabbitmq(topic交换器高级操作)

    一.topic交换器为主题交换器,可以根据路由key模糊匹配 实现模型图 二.实战 1.引入maven <dependency> <groupId>org.springfram ...

  3. Windows Azure Service Bus (5) 主题(Topic) 使用VS2013开发Service Bus Topic

    <Windows Azure Platform 系列文章目录> 项目文件,请在这里下载 在笔者之前的文章中Windows Azure Service Bus (1) 基础 介绍了Servi ...

  4. RabbitMQ 主题

    RabbitMQ (三) 发布/订阅 RabbitMQ主题 RabbitMQ Tutorials

  5. spring boot整合RabbitMQ(Topic模式)

    1.Topic交换器介绍 Topic Exchange 转发消息主要是根据通配符. 在这种交换机下,队列和交换机的绑定会定义一种路由模式,那么,通配符就要在这种路由模式和路由键之间匹配后交换机才能转发 ...

  6. MQTT主题Topic讲解

    文章转载于https://www.cnblogs.com/hayasi/p/7792191.html 我们已经把相关的连接报文搞定了.笔者想来想去还是决定先讲解一下订阅报文(SUBSCRIBE ).如 ...

  7. RabbitMQ入门(5)——主题(Topic)

    前面我们介绍了通过使用direct exchage,改善了fanout exchange只能进行虚拟广播的方式.尽管如此,直接交换也有自身的局限,它不能基于多个条件路由. 在我们的日志系统中,也许我们 ...

  8. RabbitMQ主题模式

    Send类 package topics; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; imp ...

  9. RabbitMQ之Topic交换器模式开发

    Topic交换器,即主题模式,进行规则匹配. 一.Provider 配置文件 spring.application.name=provider spring.rabbitmq.host=192.168 ...

随机推荐

  1. [转]backbone.js template()函数

    本文转自:http://book.2cto.com/201406/43974.html 本文所属图书 > Backbone.js实战 资深Web开发专家根据Backbone js最新版本撰写,对 ...

  2. Oracle的Numer类型与C,C#数据类型对应关系

    最近一直在编和Oracle数据库相关程序.Oracle的Number类型和C语言,C#语言类型的对应关系,在网络上查找很久,也没有找到说明文字.但在http://oracle.chinaitlab.c ...

  3. BZOJ1029: [JSOI2007]建筑抢修[模拟 贪心 优先队列]

    1029: [JSOI2007]建筑抢修 Time Limit: 4 Sec  Memory Limit: 162 MBSubmit: 3785  Solved: 1747[Submit][Statu ...

  4. 给ros安装arbotix simulator仿真环境

    首先下载程序包.编译.安装. cd ~/catkin_ws/src git clone https://github.com/pirobot/rbx1.git cd rbx1 git checkout ...

  5. 一个简单的socket程序运行与抓包查看

    为了熟悉socket编程,在ubuntu下运行了一个现有例子(Networking and Socket programming tutorial in C - CodeProject),并通过抓包查 ...

  6. iOS 关于版本升级问题的解决

    从iOS8系统开始,用户可以在设置里面设置在WiFi环境下,自动更新安装的App.此功能大大方便了用户,但是一些用户没有开启此项功能,因此还是需要在程序里面提示用户的. 虽然现在苹果审核不能看到版本提 ...

  7. Navigator 对象

    Navigator 对象 Navigator 对象包含有关浏览器的信息. 注意: 没有应用于 navigator 对象的公开标准,不过所有浏览器都支持该对象. Navigator 对象属性 属性 说明 ...

  8. 如何用javac 和java 编译运行整个Java工程 (转载)【转】在Linux下编译与执行Java程序

    如何用javac 和java 编译运行整个Java工程 (转载)  http://blog.csdn.net/huagong_adu/article/details/6929817 [转]在Linux ...

  9. CentOS 6.6 安装redmine

    Redmine是一个开源的.基于Web的项目管理和缺陷跟踪工具.它用日历和甘特图辅助项目及进度可视化显示.同时它又支持多项目管理.Redmine是一个自由开放源码软件解决方案,它提供集成的项目管理功能 ...

  10. SQL server 专业词汇

    sql组成:DDL:数据库模式定义语言,关键字:createDML:数据操纵语言,关键字:Insert.delete.updateDCL:数据库控制语言 ,关键字:grant.removeDQL:数据 ...