主题
(使用Java客户端)
在我们的记录系统中,我们可能想订阅不仅根据严重性的日志,还可以根据源发出日志。你可能知道这个概念从UNIX 系统日志工具,它记录路由基于两严重性(信息/警告/暴击...)和设备(AUTH / cron/ KERN ...)。
这会给我们很大的灵活性 - 我们可能想听听来自通过“cron”也是从"kern"来的所有日志的严重错误。
为了实现我们的测井系统,我们需要了解一个更复杂的话题交换(topic exchange)。
主题交流
发送到一个主题交换的消息不能有任意 routing_key的 -它必须是一个单词列表,以点分隔。这句话可以是任何东西,但他们通常指定连接到该消息的某些功能。一些有效的路由主要例子:“ stock.usd.nyse “,”nyse.vmw “,” quick.orange.rabbit “。有很多的话可以在路由的关键,只要你喜欢,高达255字节的限制。
绑定键(bingding key)也必须以同样的形式。话题交换背后的逻辑 是类似于一个直接交换 -一个消息发送给特定的路由键(routing key)将被传递到所有队列匹配结合键约束。然而,有两个重要的特殊情况,绑定键(banding keys):
- * (star) can substitute for exactly one word.
- # (hash) can substitute for zero or more words.
-
这是最简单的一个例子解释:
在这个例子中,我们将发送描述动物的消息。该消息将被发送一个路由键包含三个字(两个点)。在路由键将第一个字形容速度快,第二个颜色和第三物种:“ 兼容的<speed>.<colour>.<species> “。
我们创建了三个绑定:Q1势必具有约束力键“ *.orange.* “和Q2与” *.*.rabbit “和” lazy.# “。
这些绑定可以概括为:
- Q1是感兴趣的所有橙色的动物。
- Q2希望听到所有关于兔子,一切有关懒惰的动物。
-
具有路由键设置为“ quick.orange.rabbit “ 一则消息将被传递到两个队列。还将消息“ lazy.orange.elephant “他们都去。另一方面“ quick.orange.fox “只会去到第一队列,的” lazy.brown.fox “第二只。将被交付“ lazy.pink.rabbit “第二队列只有一次,即使它匹配两个绑定。“ quick.brown.fox “不匹配任何有约束力的,所以它会被丢弃。
如果我们打破我们的合同,并发送带有一个或四个字,如“ 橙色 “或” quick.orange.male.rabbit “,会发生什么事?那么,这些消息将不会匹配任何绑定,将会丢失。
另一方面“ lazy.orange.male.rabbit “,即使它有四个词,将匹配最后的绑定,将被传递到第二队列。
主题交流
主题交流是强大的,可以像其他交易所。
当队列“ # “(哈希)结合键绑定-将收到的所有邮件,不管扇交换路由键-像。
当特殊字符“ * “(星号)和” # “(井)不使用绑定的话题交换行为就像一个直接的。
全部放在一起
我们要在我们的记录系统使用一个话题交换。我们会启动关闭与工作假设日志将路由键有两句话:“ <facility> <severity> “。
该代码是在前面的教程中几乎是一样的 。具有路由键设置为“ quick.orange.rabbit “ 一则消息将被传递到两个队列。还将消息“lazy.orange.elephant “他们都去。另一方面“ quick.orange.fox “只会去到第一队列,的”lazy.brown.fox “第二只。将被交付“ lazy.pink.rabbit “第二队列只有一次,即使它匹配两个绑定。“quick.brown.fox “不匹配任何有约束力的,所以它会被丢弃。 -
如果我们打破我们的合同,并发送带有一个或四个字,如“ 橙色 “或” quick.orange.male.rabbit “,会发生什么事?那么,这些消息将不会匹配任何绑定,将会丢失。
另一方面“ lazy.orange.male.rabbit “,即使它有四个词,将匹配最后的绑定,将被传递到第二队列。
主题交流
主题交流是强大的,可以像其他交易所。
当队列“ # “(哈希)结合键绑定-将收到的所有邮件,不管扇交换路由键-像。
当特殊字符“ * “(星号)和” # “(井)不使用绑定的话题交换行为就像一个直接的。
全部放在一起
我们要在我们的记录系统使用一个话题交换。我们会启动关闭与工作假设日志将路由键有两句话:“<facility> <severity> “。
该代码是在前面的教程中几乎是一样的 。
EmitLogTopic.java的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
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 routingKey = getRouting(argv); String message = getMessage(argv); channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes()); System.out.println(" [x] Sent '" + routingKey + "':'" + message + "'"); connection.close(); } //... }
ReceiveLogsTopic.java的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
public class ReceiveLogsTopic { 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(); if (argv.length < 1){ System.err.println("Usage: ReceiveLogsTopic [binding_key]..."); System.exit(1); } for(String bindingKey : argv){ channel.queueBind(queueName, EXCHANGE_NAME, bindingKey); } System.out.println(" [*] Waiting for 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 + "':'" + message + "'"); } } }
运行下面的例子,包括在classpath 教程1 -在Windows上,使用%CP%。
要接收所有的日志:
$ java -cp $CP ReceiveLogsTopic "#"
要接收设施““ 的所有日志:$ java -cp $CP ReceiveLogsTopic "kern.*"
或者,如果你想听到关于 "critical"的日志:
$ java -cp $CP ReceiveLogsTopic "*.critical"
您可以创建多个绑定:
$ java -cp $CP ReceiveLogsTopic "kern.*" "*.critical"
发出日志与一个路由键(routing key)“ kern.critical “的类型:
$ java -cp $CP EmitLogTopic "kern.critical" "A critical kernel error"
玩得开心玩这些程序。请注意,代码不作任何假设路由或绑定键,你可能想发挥两个以上路由的关键参数。
一些玩笑:
- “ * “的绑定将赶上一个空路由密钥发送的消息?
- 将“ #* “抓的消息字符串” “ 作为一个关键呢?它会赶上一个字键的消息?
- 不同的是“ 一个*# “,从” A# “?
(完整的源代码为EmitLogTopic.java ReceiveLogsTopic.java)
接下来,找出如何做一个往返消息作为一个远程过程调用教程6