一、模式說明
路由模式特點:
- 佇列與交換機的繫結,不能是任意繫結了,而是要指定一個 RoutingKey (路由key)
- 訊息的傳送方在 向 Exchange傳送訊息時,也必須指定訊息的 RoutingKey 。
- Exchange不再把訊息交給每一個繫結的佇列,而是根據訊息的 Routing Key 進行判斷,只有佇列的 Routingkey 與訊息的 Routing key 完全一致,才會接收到訊息
圖解:
- P:生產者,向Exchange傳送訊息,傳送訊息時,會指定一個routing key。
- X:Exchange(交換機),接收生產者的訊息,然後把訊息遞交給 與routing key完全匹配的佇列
- C1:消費者,其所在佇列指定了需要routing key 為 error 的訊息
- C2:消費者,其所在佇列指定了需要routing key 為 info、error、warning 的訊息
二、程式碼
在編碼上與
Publish/Subscribe釋出與訂閱模式
的區別是交換機的型別為:Direct,還有佇列繫結交換機的時候需要指定routing key。
①生產者
package com.itheima.rabbitmq.routing;
import com.itheima.rabbitmq.util.ConnectionUtil;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
/**
* 路由模式的交換機型別為:direct
*/
public class Producer {
//交換機名稱
static final String DIRECT_EXCHAGE = "direct_exchange";
//佇列名稱
static final String DIRECT_QUEUE_INSERT = "direct_queue_insert";
//佇列名稱
static final String DIRECT_QUEUE_UPDATE = "direct_queue_update";
public static void main(String[] args) throws Exception {
//建立連線
Connection connection = ConnectionUtil.getConnection();
// 建立頻道
Channel channel = connection.createChannel();
/**
* 宣告交換機
* 引數1:交換機名稱
* 引數2:交換機型別,fanout、topic、direct、headers
*/
channel.exchangeDeclare(DIRECT_EXCHAGE, BuiltinExchangeType.DIRECT);
// 宣告(建立)佇列
/**
* 引數1:佇列名稱
* 引數2:是否定義持久化佇列
* 引數3:是否獨佔本次連線
* 引數4:是否在不使用的時候自動刪除佇列
* 引數5:佇列其它引數
*/
channel.queueDeclare(DIRECT_QUEUE_INSERT, true, false, false, null);
channel.queueDeclare(DIRECT_QUEUE_UPDATE, true, false, false, null);
//佇列繫結交換機
channel.queueBind(DIRECT_QUEUE_INSERT, DIRECT_EXCHAGE, "insert");
channel.queueBind(DIRECT_QUEUE_UPDATE, DIRECT_EXCHAGE, "update");
// 傳送資訊
String message = "新增了商品。路由模式;routing key 為 insert " ;
/**
* 引數1:交換機名稱,如果沒有指定則使用預設Default Exchage
* 引數2:路由key,簡單模式可以傳遞佇列名稱
* 引數3:訊息其它屬性
* 引數4:訊息內容
*/
channel.basicPublish(DIRECT_EXCHAGE, "insert", null, message.getBytes());
System.out.println("已傳送訊息:" + message);
// 傳送資訊
message = "修改了商品。路由模式;routing key 為 update" ;
/**
* 引數1:交換機名稱,如果沒有指定則使用預設Default Exchage
* 引數2:路由key,簡單模式可以傳遞佇列名稱
* 引數3:訊息其它屬性
* 引數4:訊息內容
*/
channel.basicPublish(DIRECT_EXCHAGE, "update", null, message.getBytes());
System.out.println("已傳送訊息:" + message);
// 關閉資源
channel.close(); connection.close();
}
}
②消費者1
package com.itheima.rabbitmq.routing;
import com.itheima.rabbitmq.util.ConnectionUtil;
import com.rabbitmq.client.*;
import java.io.IOException;
public class Consumer1 {
public static void main(String[] args) throws Exception {
Connection connection = ConnectionUtil.getConnection();
// 建立頻道
Channel channel = connection.createChannel();
//宣告交換機
channel.exchangeDeclare(Producer.DIRECT_EXCHAGE, BuiltinExchangeType.DIRECT);
// 宣告(建立)佇列
/**
* 引數1:佇列名稱
* 引數2:是否定義持久化佇列
* 引數3:是否獨佔本次連線
* 引數4:是否在不使用的時候自動刪除佇列
* 引數5:佇列其它引數
*/
channel.queueDeclare(Producer.DIRECT_QUEUE_INSERT, true, false, false, null);
//佇列繫結交換機
channel.queueBind(Producer.DIRECT_QUEUE_INSERT, Producer.DIRECT_EXCHAGE, "insert");
//建立消費者;並設定訊息處理
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
/**
* consumerTag 訊息者標籤,在channel.basicConsume時候可以指定
* envelope 訊息包的內容,可從中獲取訊息id,訊息routingkey,交換機,訊息和重傳標誌(收到訊息失敗後是否需要重新傳送)
* properties 屬性資訊
* body 訊息
*/
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key為:" + envelope.getRoutingKey());
//交換機
System.out.println("交換機為:" + envelope.getExchange());
//訊息id
System.out.println("訊息id為:" + envelope.getDeliveryTag());
//收到的訊息
System.out.println("消費者1-接收到的訊息為:" + new String(body, "utf-8"));
}
};
//監聽訊息
/**
* 引數1:佇列名稱
* 引數2:是否自動確認,設定為true為表示訊息接收到自動向mq回覆接收到了,mq接收到回覆會刪除訊息,設定為false則需要手動確認
* 引數3:訊息接收到後回撥
*/
channel.basicConsume(Producer.DIRECT_QUEUE_INSERT, true, consumer);
}
}
③消費者2
package com.itheima.rabbitmq.routing;
import com.itheima.rabbitmq.util.ConnectionUtil;
import com.rabbitmq.client.*;
import java.io.IOException;
public class Consumer2 {
public static void main(String[] args) throws Exception {
Connection connection = ConnectionUtil.getConnection();
// 建立頻道
Channel channel = connection.createChannel();
//宣告交換機
channel.exchangeDeclare(Producer.DIRECT_EXCHAGE, BuiltinExchangeType.DIRECT);
// 宣告(建立)佇列
/**
* 引數1:佇列名稱
* 引數2:是否定義持久化佇列
* 引數3:是否獨佔本次連線
* 引數4:是否在不使用的時候自動刪除佇列
* 引數5:佇列其它引數
*/
channel.queueDeclare(Producer.DIRECT_QUEUE_UPDATE, true, false, false, null);
//佇列繫結交換機
channel.queueBind(Producer.DIRECT_QUEUE_UPDATE, Producer.DIRECT_EXCHAGE, "update");
//建立消費者;並設定訊息處理
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
/**
* consumerTag 訊息者標籤,在channel.basicConsume時候可以指定
* envelope 訊息包的內容,可從中獲取訊息id,訊息routingkey,交換機,訊息和重傳標誌(收到訊息失敗後是否需要重新傳送)
* properties 屬性資訊
* body 訊息
*/
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key為:" + envelope.getRoutingKey());
//交換機
System.out.println("交換機為:" + envelope.getExchange());
//訊息id
System.out.println("訊息id為:" + envelope.getDeliveryTag());
//收到的訊息
System.out.println("消費者2-接收到的訊息為:" + new String(body, "utf-8"));
}
};
//監聽訊息
/**
* 引數1:佇列名稱
* 引數2:是否自動確認,設定為true為表示訊息接收到自動向mq回覆接收到了,mq接收到回覆會刪除訊息,設定為false則需要手動確認
* 引數3:訊息接收到後回撥
*/
channel.basicConsume(Producer.DIRECT_QUEUE_UPDATE, true, consumer);
}
}
三、測試
啟動所有消費者,然後使用生產者傳送訊息;在消費者對應的控制檯可以檢視到生產者傳送對應 routing key 對應佇列的訊息;到達
按照需要接收的效果。
在執行完測試程式碼後,其實到RabbitMQ的管理後臺找到 Exchanges 選項卡,點選
direct_exchange
的交換機,可以檢視到如下的繫結:
四、小結
Routing模式要求佇列在繫結交換機時要指定routing key,訊息會轉發到符合routing key的佇列。
喜歡這篇文章的朋友們可以關注個人簡介中的公眾號
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69964492/viewspace-2768350/,如需轉載,請註明出處,否則將追究法律責任。