RabbitMQ精講3:Exchange交換機類型-direct、topic、fanout

目錄

前言

1. Exchange概念

2. 交換機屬性

3. Direct Exchange(直連)

3.1 Direct Exchange(直連)代碼演示

生產端:

消費端:

queueDeclare 說明 

測試結果:

4. Topic Exchange

4.1 Topic Exchange代碼演示

Topic Exchange生產端:

Topic Exchange消費端:

Topic Exchange測試結果:

5. Fanout Exchange

5.1 Fanout Exchange代碼演示

Fanout Exchange生產端:

Fanout Exchange消費端:

6. Exchange交換機其他屬性

6.1 Bingding —— 綁定

6.2 Queue——消息隊列

6.3 Message——消息

6.4 其他屬性

6.5 Virtual Host虛擬主機


前言

來了解RabbitMQ一個重要的概念:Exchange交換機

1. Exchange概念

Exchange:接收消息,並根據路由鍵轉發消息所綁定的隊列。

Exchange

 

  • 藍色框:客戶端發送消息至交換機,通過路由鍵路由至指定的隊列。
  • 黃色框:交換機和隊列通過路由鍵有一個綁定的關係。
  • 綠色框:消費端通過監聽隊列來接收消息。

2. 交換機屬性

交換機屬性

 

  • Name:交換機名稱
  • Type:交換機類型——direct、topic、fanout、headers、sharding(此篇不講)
  • Durability:是否需要持久化,true爲持久化
交換機屬性
  • Auto Delete:當最後一個綁定到Exchange上的隊列刪除後,自動刪除該Exchange
  • Internal:當前Exchange是否用於RabbitMQ內部使用,默認爲false
  • Arguments:擴展參數,用於擴展AMQP協議自定製化使用

3. Direct Exchange(直連)

Direct Exchange(直連)

 

  • 所有發送到Direct Exchange的消息被轉發到RouteKey中指定的Queue
  • 注意:Direct模式可以使用RabbitMQ自帶的Exchange:default Exchange,所以不需要將Exchange進行任何綁定(binding)操作,消息傳遞時,RouteKey必須完全匹配纔會被隊列接收,否則該消息會被拋棄。
Direct Exchange(直連)
  • 重點:routing key與隊列queues 的key保持一致,即可以路由到對應的queue中。

3.1 Direct Exchange(直連)代碼演示

我們來看下大概步驟:

  • ConnectionFacorty:獲取連接工廠
  • Connection:一個連接
  • Channel:數據通信信道,可發送和接收消息
  • Queue:具體的消息存儲隊列
  • Producer & Consumer 生產者和消費者
    • 這個連接工廠需要配置一些相應的信息,例如: RabbitMQ節點的地址,端口號,VirtualHost等等。
  • Channel是我們RabbitMQ所有消息進行交互的關鍵。

生產端:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Producer4DirectExchange {

	
	public static void main(String[] args) throws Exception {
		
		//1 創建ConnectionFactory
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.11.76");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		//2 創建Connection
		Connection connection = connectionFactory.newConnection();
		//3 創建Channel
		Channel channel = connection.createChannel();  
		//4 聲明
		String exchangeName = "test_direct_exchange";
		String routingKey = "test.direct111";
		//5 發送
		
		String msg = "Hello World RabbitMQ 4  Direct Exchange Message 111 ... ";
		channel.basicPublish(exchangeName, routingKey , null , msg.getBytes()); 		
		
	}
	
}

消費端:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;

public class Consumer4DirectExchange {

	public static void main(String[] args) throws Exception {
		
		
        ConnectionFactory connectionFactory = new ConnectionFactory() ;  
        
        connectionFactory.setHost("192.168.11.76");
        connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(3000);
        Connection connection = connectionFactory.newConnection();
        
        Channel channel = connection.createChannel();  
		//4 聲明
		String exchangeName = "test_direct_exchange";
		String exchangeType = "direct";
		String queueName = "test_direct_queue";
		String routingKey = "test.direct";
		
		//表示聲明瞭一個交換機
		channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
		//表示聲明瞭一個隊列
		channel.queueDeclare(queueName, false, false, false, null);
		//建立一個綁定關係:
		channel.queueBind(queueName, exchangeName, routingKey);
		
        //durable 是否持久化消息
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //參數:隊列名稱、是否自動ACK、Consumer
        channel.basicConsume(queueName, true, consumer);  
        //循環獲取消息  
        while(true){  
            //獲取消息,如果沒有消息,這一步將會一直阻塞  
            Delivery delivery = consumer.nextDelivery();  
            String msg = new String(delivery.getBody());    
            System.out.println("收到消息:" + msg);  
        } 
	}
}

queueDeclare 說明 

channel.queueDeclare(queueName, true, false, false, null);
  • 第一個參數:queuename:隊列的名稱
  • 第二個參數:durable 是否持久化。true消息會持久化到本地,保證重啓服務後消息不會丟失
  • 第三個參數:exclusive :表示獨佔方式,設置爲true 在某些情景下有必要,例如:順序消費。表示只有一個channel可以去監聽,其他channel都不能夠監聽。目的就是爲了保證順序消費。
  • 第四個參數:autoDelete:隊列如果與Exchange未綁定,則自動刪除
  • 第五個參數:arguments:擴展參數

測試結果:

注意需要routingKey保持一致。可以自己嘗試修改routingkey,是否能收到消息。

4. Topic Exchange

Topic Exchange
  • 所有發送到Topic Exchange的消息被轉發到所有管線RouteKey中指定Topic的Queue上
  • Exchange將RouteKey和某Topic進行模糊匹配,此時隊列需要綁定一個Topic
Topic Exchange
Topic Exchange

在一堆消息中,每個不同的隊列只關心自己需要的消息。

4.1 Topic Exchange代碼演示

Topic Exchange生產端:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Producer4TopicExchange {

	
	public static void main(String[] args) throws Exception {
		
		//1 創建ConnectionFactory
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.11.76");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		//2 創建Connection
		Connection connection = connectionFactory.newConnection();
		//3 創建Channel
		Channel channel = connection.createChannel();  
		//4 聲明
		String exchangeName = "test_topic_exchange";
		String routingKey1 = "user.save";
		String routingKey2 = "user.update";
		String routingKey3 = "user.delete.abc";
		//5 發送
		
		String msg = "Hello World RabbitMQ 4 Topic Exchange Message ...";
		channel.basicPublish(exchangeName, routingKey1 , null , msg.getBytes()); 
		channel.basicPublish(exchangeName, routingKey2 , null , msg.getBytes()); 	
		channel.basicPublish(exchangeName, routingKey3 , null , msg.getBytes()); 
		channel.close();  
        connection.close();  
	}
	
}

Topic Exchange消費端:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;

public class Consumer4TopicExchange {

	public static void main(String[] args) throws Exception {
		
		
        ConnectionFactory connectionFactory = new ConnectionFactory() ;  
        
        connectionFactory.setHost("192.168.11.76");
        connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(3000);
        Connection connection = connectionFactory.newConnection();
        
        Channel channel = connection.createChannel();  
		//4 聲明
		String exchangeName = "test_topic_exchange";
		String exchangeType = "topic";
		String queueName = "test_topic_queue";
		//String routingKey = "user.*";
		String routingKey = "user.*";
		// 1 聲明交換機 
		channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
		// 2 聲明隊列
		channel.queueDeclare(queueName, false, false, false, null);
		// 3 建立交換機和隊列的綁定關係:
		channel.queueBind(queueName, exchangeName, routingKey);
		
        //durable 是否持久化消息
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //參數:隊列名稱、是否自動ACK、Consumer
        channel.basicConsume(queueName, true, consumer);  
        //循環獲取消息  
        while(true){  
            //獲取消息,如果沒有消息,這一步將會一直阻塞  
            Delivery delivery = consumer.nextDelivery();  
            String msg = new String(delivery.getBody());    
            System.out.println("收到消息:" + msg);  
        } 
	}
}

Topic Exchange測試結果:

注意一個問題:需要進行解綁

5. Fanout Exchange

Fanout Exchange
  • 不處理路由鍵,只需要簡單的將隊裏綁定到交換機上
  • 發送到交換機的消息都會被轉發到與該交換機綁定的所有隊列上
  • Fanout交換機轉發消息是最快的

5.1 Fanout Exchange代碼演示

Fanout Exchange生產端:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Producer4FanoutExchange {

	
	public static void main(String[] args) throws Exception {
		
		//1 創建ConnectionFactory
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.11.76");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
		//2 創建Connection
		Connection connection = connectionFactory.newConnection();
		//3 創建Channel
		Channel channel = connection.createChannel();  
		//4 聲明
		String exchangeName = "test_fanout_exchange";
		//5 發送
		for(int i = 0; i < 10; i ++) {
			String msg = "Hello World RabbitMQ 4 FANOUT Exchange Message ...";
			channel.basicPublish(exchangeName, "", null , msg.getBytes()); 			
		}
		channel.close();  
        connection.close();  
	}
	
}

Fanout Exchange消費端:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;

public class Consumer4FanoutExchange {

	public static void main(String[] args) throws Exception {
		
        ConnectionFactory connectionFactory = new ConnectionFactory() ;  
        
        connectionFactory.setHost("192.168.11.76");
        connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		
        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(3000);
        Connection connection = connectionFactory.newConnection();
        
        Channel channel = connection.createChannel();  
		//4 聲明
		String exchangeName = "test_fanout_exchange";
		String exchangeType = "fanout";
		String queueName = "test_fanout_queue";
		String routingKey = "";	//不設置路由鍵
		channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
		channel.queueDeclare(queueName, false, false, false, null);
		channel.queueBind(queueName, exchangeName, routingKey);
		
        //durable 是否持久化消息
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //參數:隊列名稱、是否自動ACK、Consumer
        channel.basicConsume(queueName, true, consumer); 
        //循環獲取消息  
        while(true){  
            //獲取消息,如果沒有消息,這一步將會一直阻塞  
            Delivery delivery = consumer.nextDelivery();  
            String msg = new String(delivery.getBody());    
            System.out.println("收到消息:" + msg);  
        } 
	}
}

6. Exchange交換機其他屬性

6.1 Bingding —— 綁定

標題

 

  • Exchange和Exchange、Queue之間的連接關係
  • Bingding可以包含RoutingKey或者參數

6.2 Queue——消息隊列

Queue——消息隊列
  • 消息隊列,實際存儲消息數據
  • Durability:是否持久化,Durable:是 ,Transient:否
  • Auto delete:如選yes,代表當最後一個監聽被移除之後,該Queue會自動被刪除。

6.3 Message——消息

Message——消息

 

  • 服務器與應用程序之間傳送的數據
  • 本質上就是一段數據,由Properties和Payload(Body)組成
  • 常用屬性:delivery mode、headers(自定義屬性)

6.4 其他屬性

 

  • content_type、content_encoding、priority
  • correlation_id、reply_to、expiration、message_id
  • timestamp、type、user_id、app_id、cluster_id

6.5 Virtual Host虛擬主機

Virtual Host虛擬主機

 

  • 虛擬地址,用於進行邏輯隔離,最上層的消息路由
  • 一個Virtual Host裏面可以有若干個Exchange和Queue
  • 同一個Virtual Host裏面不能有相同名稱的Exchange或Queue

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章