在前篇文章中我们改进了我们的日志系统,我们利用direct
类型的exchange替代了仅能够简单广播的fanout
类型的exchange,并且获得了选择接受日志的可能。
虽然利用direct
类型的exchange改进了我们的系统,但它仍然有局限性,它无法基于多个条件进行导航。
在我们的日志系统中我们可能想订阅的不仅仅是基于消息严重性的日志信息,也想订阅基于这日志消息的来源(这日志消息是被谁发送的)。你可能从syslog unix tool
中了解到路由日志是基于严重性(info/warn/crit…)和设备(auth/cron/kern…)的这种概念。
这将给我一些灵活性,我们可能想听到仅来自于cron
的错误信息和来自kern
的所有日志信息。
为了在我们的日志实现这个效果我们需要学习一个更复杂的topic
类型的exchange。
Topic exchange
消息被发送到topic
类型的exchange 不能是任意路由关键字,这个路由关键字必须是一个以小圆点间隔的单词组。这单词可以是任意的,但他们通常描述了关于这个消息的一些特征。在路由关键字中可以有尽可能多的单词,最大长度是255bytes。
binding关键字也必须是相同的形式,topic
类型的exchange背后的逻辑与direct
类型的exhange是相似的,一个含有特定路由关键字的消息将被传递到binding关键字匹配的全部队列中。
这里有两个关于binding关键字的特殊情况:
*
代表一个单词
#
代表0个或多个单词
在这个例子中,我们打算发送全部都是描述动物的消息。这消息和由三个单词两个小圆点组成的路由关键字将被发送。路由关键字中的第一个单词将描述速度、第二个描述颜色、第三个描述物种:”..”。
我们创建了三个bindings:
Q1队列绑定*.orange.*
这个binding关键字
Q2队列绑定*.*.rabbit
、lazy.#
这两个binding关键字
这些binding能够被概括为:
Q1队列对全部橙色动物感兴趣
Q2队列想听到关于兔子和速度慢吞吞的动物的所有事情
一个路由关键字被设置为quick.orange.rabbit
的消息将被传递到这两个队列中。路由关键字为lazy.orange.elephant
的消息也将进入这两个队列中。在另一方面,路由关键字为quick.orange.fox
的消息将仅进入第一个队列,路由关键字为lazy.brown.fox
的消息仅进入第二个队列。路由关键字为lazy.pink.rabbit
的消息虽然匹配两个binding但这个消息只会被传递到第二个队列一次。路由关键字quick.brown.fox
消息没有匹配到任何binding所以它将被丢弃。
如果我们打破上面的这种规则使被发送消息的路由关键字有一个或四个单词,像orange
、quick.orange.male.rabbit
这样,会发生什么呢?结果是这些消息无法匹配到任意的binding以至于它们将被丢失。
另一方面lazy.orange.male.rabbit
虽然有四个单词,但它将匹配最后一个binding并将被传递到第二个队列中。如果你不明白为什么会出现这两个不一样的情况,那么请回到上面关于讲解#
含义的部分。
Topic exchange
topic类型的exchange是强大的且能够表现的像其它类型的exchange。
当一个队列被绑定时其binding关键字为#
,则它将接收全部的消息而不考虑路由关键字,像fanout
类型的exchange一样。
当特殊字符*
、#
没有被用于binding关键字时,topic
类型的exchange将表现的像direct
类型的exchange一样。
我们打算在我们的日志系统中使用topic
类型的exchange。我们先假定日志消息的路由关键字由两个单词组成,其格式为:<facility>.<severity>
。
这代码与前篇文章中的大部分相似。
javac -cp %CP% ReceiveLogsTopic.java EmitLogTopic.java
接收全部的日志:
java -cp $CP ReceiveLogsTopic "#"
接收来自kern
设备的全部消息:
java -cp $CP ReceiveLogsTopic "kern.*"
如果你想仅听到关于critical
的日志信息:
java -cp $CP ReceiveLogsTopic "*.critical"
你能创建多个binding
java -cp $CP ReceiveLogsTopic "kern.*" "*.critical"
设置被发送日志的路由关键字为”kern.critical” :
java -cp $CP EmitLogTopic "kern.critical" "A critical kernel error"
本篇内容的代码稍后再补充