在說正題以前先解釋一下交換機模式是個籠統的稱呼,它不是一個單獨的模式(包括了訂閱模式,路由模式和主題模式),交換機模式是一個比較經常使用的模式,主要是爲了實現數據的同步。java
首先,說一下訂閱模式,就和字面上的意思差很少主要就是一個生產者,多個消費者,同一個消息被多個消費者獲取,先看一下官網的圖示sql
總體執行過程就和圖裏同樣,生產者把消息發送到交換機,而後隊列綁定到交換機,消息由交換機發送到隊列,每個隊列都有一個各自的消費者。這樣spa
就實現了一個消息被多個消費者所獲取,並且若是有新的消費者加入直接綁定隊列到交換機就能夠了,大大的下降了系統間的耦合度。還有一點要注意的就是3d
當咱們把消息發送到一個沒有隊列綁定的交換機時,消息就會丟失,由於消息只能存儲在隊列,而交換機只作交換,不作存儲!code
生產者代碼: blog
public class Send { private final static String EXCHANGE_NAME = "exchange_name"; //交換機名稱 public static void main(String[] argv) throws Exception { // 獲取MQ鏈接和通道 Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); // 聲明交換機 channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); // 消息內容 String message = "生產者消息"; channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes()); System.out.println(" 發送 '" + message + "'"); channel.close(); connection.close(); } }
消費者一號代碼:隊列
public class Recv { private final static String QUEUE_NAME = "test_queue_ex"; private final static String EXCHANGE_NAME = "exchange_name"; public static void main(String[] argv) throws Exception { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); // 聲明隊列 channel.queueDeclare(QUEUE_NAME, false, false, false, null); // 綁定隊列到交換機 channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); channel.basicQos(1); // 定義隊列的消費者 QueueingConsumer consumer = new QueueingConsumer(channel); // 監聽隊列,手動返回完成 channel.basicConsume(QUEUE_NAME, false, consumer); // 獲取消息 while (true) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" 消費者一號 '" + message + "'"); Thread.sleep(10); channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); } } }
消費者二號代碼:路由
public class Recv2 { private final static String QUEUE_NAME = "test_queue_ex2"; private final static String EXCHANGE_NAME = "exchange_name"; public static void main(String[] argv) throws Exception { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); channel.basicQos(1); QueueingConsumer consumer = new QueueingConsumer(channel); channel.basicConsume(QUEUE_NAME, false, consumer); while (true) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println("消費者二號 '" + message + "'"); Thread.sleep(10); channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); } } }
運行代碼以後能夠看到get
生產者發送的消息已經存儲在了交換機之中。查看綁定關係以下圖所示:同步
因此,能夠得出結論一個消息被多個消費者所消費。訂閱模式也存在着缺陷有時並非全部數據都須要同步,因此用訂閱模式來作數據同步並不合理。因而就用到了路由模式。
官網圖示以下:
和訂閱模式比較相似,只是type變成了direct類型,路由模式也是先由生產者發送消息到交換機,而後在根據綁定鍵來判斷消息發送到哪個交換機。以下圖:
和訂閱模式的區別就是生產者發送消息時要先聲明消息的類型,也就是說消息會被哪類消費者所獲取
消費者和生產者保持一個類型的時候,就能夠接收到對應生產者所發送的消息了。從而能夠過濾掉不須要的消息類型。
主題模式我的感受就和sql語句裏的like關鍵字同樣,不用保證消息類型同樣,只要保證其類似就能夠接收消息了,相比於路由模式,
主題模式匹配率比較低,可是功能確提升了不少,減小了路由key的建立,如圖所示:
type變成了topic類型,至於其餘方面和路由模式同樣就很少說了。