4、主題(Topic)
上一篇博客中,我們進步改良了我們的日誌系統。我們使用direct類型轉發器,使得接收者有能力進行選擇性的接收日誌,,而非fanout那樣,只能夠無腦的轉發。
雖然使用direct類型改良了我們的系統,但是仍然存在一些侷限性:它不能夠基於多重條件進行路由選擇。
接下來我們學習稍微複雜的主題類型的轉發器(topic exchange)
1、主題轉發(TopicExchange)
發往主題類型的轉發器的消息不能隨意的設置選擇鍵(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不能與任何綁定鍵匹配,所以會被丟棄。
注:主題類型的轉發器非常強大,可以實現其他類型的轉發器。
當一個隊列與綁定鍵#綁定,將會收到所有的消息,類似fanout類型轉發器。
當綁定鍵中不包含任何#與*時,類似direct類型轉發器。
3、 完整的例子
發送端:
public class producer6 {
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 consumer6_1 {
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:
channel.queueBind(queueName, EXCHANGE_NAME,"kernel.*");
其它代碼同接收端1
運行結果:
[x] SentroutingKey = 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 formessages about kernel. To exit press CTRL+C
[x] Received routingKey = kernel.critical,msg =f65d3e1a-0619-4f85-8b0d-59375380ecc9.
---------------------------------------------------
[*] Waiting forcritical 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