注:這是RabbitMQ-java版Client的指導(dǎo)教程翻譯系列文章戈咳,歡迎大家批評(píng)指正
第一篇Hello Word了解RabbitMQ的基本用法
第二篇Work Queues介紹隊(duì)列的使用
第三篇Publish/Subscribe介紹轉(zhuǎn)換器以及其中fanout類型
第四篇Routing介紹direct類型轉(zhuǎn)換器
第五篇Topics介紹topic類型轉(zhuǎn)換器
第六篇RPC介紹遠(yuǎn)程調(diào)用
主題(Topics)
在上篇指導(dǎo)教程中我們改進(jìn)了日志系統(tǒng)待秃,替換了轉(zhuǎn)換器的類型-fanout只會(huì)愚蠢的廣播狂巢,而使用direct類型桐猬,增加選擇接受日志的能力茫船。
盡管使用direct類型的轉(zhuǎn)換器提高了我們的日志系統(tǒng)愿棋,但是它還有有一些限制:路由選擇不能路由多種條件。
在我們的日志系統(tǒng)中诈嘿,我們不僅想訂閱嚴(yán)重等級(jí)的日志堪旧,還想訂閱關(guān)于發(fā)送日志來(lái)源削葱。你可能知道這種來(lái)自u(píng)nix工具系統(tǒng)日志的概念,它路由選擇依靠于日志嚴(yán)重等級(jí)(info/warn/crit...)和設(shè)備(auth/cron/kern...)淳梦。
這樣就給了我們很大的靈活性析砸,我們可能想監(jiān)聽(tīng)來(lái)自cron設(shè)備嚴(yán)重錯(cuò)誤的日志和來(lái)自ken設(shè)備的全部日志。
為了能夠在我們的日志系統(tǒng)中實(shí)現(xiàn)上述的功能爆袍,我們需要學(xué)習(xí)一個(gè)更復(fù)雜點(diǎn)類型的轉(zhuǎn)換器:Topics首繁。
主題轉(zhuǎn)換器(Topic exchange)
發(fā)送給topic類型的轉(zhuǎn)換器沒(méi)有唯一的routing_key,它必須是一系列的字符陨囊,由點(diǎn)分開(kāi)弦疮,字符可以是任何東西,但是一般會(huì)使用詳細(xì)的特性去關(guān)聯(lián)消息蜘醋。很少有無(wú)用的key胁塞,例如:"stock.usd.nyse","nyse.vmw"堂湖,"quick.orange.rabbit"。你可以選擇任意個(gè)字符状土,但是不能超過(guò)255字節(jié)无蜂。
綁定的key必須是相同的格式,Topics類型和direct類型的轉(zhuǎn)換器背后邏輯是相似的蒙谓,發(fā)送特殊routing_key的消息將會(huì)被分發(fā)到擁有相匹配binding key的所有隊(duì)列中斥季。無(wú)論怎么樣,這里有兩種重要特殊的兩種keys:
* 代表一個(gè)單詞
# 代表零個(gè)或多個(gè)單詞
例子最容易解釋清楚:
上述例子中累驮,我們發(fā)送全是描述動(dòng)物的消息酣倾,這些消息的routing key將由三個(gè)單詞組成(兩個(gè)點(diǎn)分開(kāi)),第一個(gè)單詞描述速度谤专,第二個(gè)單詞描述顏色躁锡,第三個(gè)單詞描述種類:".."。
我們創(chuàng)建了三種綁定方式:Q1綁定key:" .orange. "置侍,Q2綁定key:" ..rabbit "和" lazy.# "映之。
這些綁定總結(jié)如下:
Q1對(duì)所有orange顏色的動(dòng)物感興趣
Q2想知道所有兔子種類的消息和所有懶惰的動(dòng)物消息。
routing key為 " quick.orange.rabbit "的消息將會(huì)被分發(fā)到這兩個(gè)隊(duì)列中蜡坊,routing key為" lazy.orange.elephant "的消息同樣會(huì)被發(fā)送到這兩個(gè)隊(duì)列中杠输。另一方面,routingkey為" quick.orange.fox "的消息只會(huì)被發(fā)送到第一個(gè)隊(duì)列中秕衙,routingkey為" lazy.brown.fox "的消息只會(huì)被發(fā)送到第二個(gè)隊(duì)列中蠢甲。routingkey為" lazy.pink.rabbit "的消息即使符合一個(gè)隊(duì)列的兩個(gè)綁定,但還是只發(fā)送一條消息到該隊(duì)列中据忘。key為" quick.brown.fox "的消息沒(méi)有匹配任何綁定鹦牛,所以將會(huì)被清除搞糕。
如果我們不顧任何的協(xié)議,發(fā)送一個(gè)routing key為一個(gè)單詞或者四個(gè)單詞的消息能岩,像"orange"或者"quick.orange.male.rabbit"寞宫,那么會(huì)怎么樣呢?顯然拉鹃,這樣的消息將不會(huì)匹配任何綁定所以會(huì)被丟失辈赋。
但是另一方面,像routing_key為" lazy.orange.male.rabbit "的消息膏燕,即使有四個(gè)單詞钥屈,但是匹配Q2隊(duì)列的綁定,所以會(huì)被發(fā)送到Q2隊(duì)列中坝辫。
主題轉(zhuǎn)換器說(shuō)明
主題轉(zhuǎn)換器是非常強(qiáng)大的篷就,并且可以像其他的轉(zhuǎn)換器一樣使用。
當(dāng)一個(gè)隊(duì)列綁定binding key為“#”近忙,它將會(huì)接收到所有的消息竭业,不管routing key為什么的消息,這就像是fanout類型的轉(zhuǎn)換器及舍。
當(dāng)一個(gè)隊(duì)列綁定中不帶有字符“ * ” 和“ # ”的時(shí)候未辆,主題轉(zhuǎn)換器跟direct轉(zhuǎn)換器是相同的。
綜合
我們將主題轉(zhuǎn)換器應(yīng)用到日志系統(tǒng)中锯玛,在routing key為兩個(gè)單詞" . "的日志消息前提下,我們開(kāi)始工作攘残。
以下的代碼和上篇指導(dǎo)文章中的很相似拙友。
下面是EmitLogTopic.java的源代碼歼郭,這里下載:
import com.rabbitmq.client.*;
import java.io.IOException;
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();
}
//...
}
下面是ReceiveLogsTopics.java的源代碼遗契,這里下載:
import java.io.IOException;
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");
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + envelope.getRoutingKey() + "':'" + message + "'");
}
};
channel.basicConsume(queueName, true, consumer);
}
}
編譯并且運(yùn)行程序,在第一篇指導(dǎo)文件中病曾,有windows的路徑說(shuō)明姊途,使用%CP%配置環(huán)境變量:
javac -cp $CP ReceiveLogsTopic.java EmitLogTopic.java
接收所有的日志:
java -cp $CP ReceiveLogsTopic "#"
接收設(shè)備為kern的日志:
java -cp $CP ReceiveLogsTopic "kern.*"
或者你想接收嚴(yán)重等級(jí)的日志:
java -cp $CP ReceiveLogsTopic "*.critical"
你也可以建立多重綁定:
java -cp $CP ReceiveLogsTopic "kern." ".critical"
最后發(fā)送routing key為" kern.critical "的消息:
java -cp $CP EmitLogTopic "kern.critical" "A critical kernel error"
希望實(shí)踐這三個(gè)程序的時(shí)候感到有趣。請(qǐng)注意關(guān)于routing key和binding key是沒(méi)有任何限制的知态,你可隨意的使用多個(gè)routing key參數(shù)捷兰。
第五節(jié)的內(nèi)容大致翻譯完了。這里是原文鏈接负敏,接著進(jìn)入下一節(jié):RPC贡茅。
終篇是我對(duì)RabbitMQ使用理解的總結(jié)文章许布,歡迎討教蜕该。
--謝謝--