每日一學:你知道如何在 RabbitMQ 中實現 Work queues工作佇列模式嗎?

無敵天驕發表於2021-04-14

一、模式說明

每日一學:你知道如何在 RabbitMQ 中實現 Work queues工作佇列模式嗎?

Work Queues 與入門程式的簡單模式相比,多了一個或一些消費端,多個消費端共同消費同一個佇列中的訊息。

應用場景 :對於任務過重或任務較多情況使用工作佇列可以提高任務處理的速度。

二、程式碼

Work Queues 與入門程式的 簡單模式 的程式碼是幾乎一樣的:可以完全複製,並複製多一個消費者進行多個消費者同時消費訊息的測試。

①生產者

package com.itheima.rabbitmq.work; 
import com.itheima.rabbitmq.util.ConnectionUtil; 
import com.rabbitmq.client.Channel; 
import com.rabbitmq.client.Connection; 
import com.rabbitmq.client.ConnectionFactory; 
public class Producer { 
    static final String QUEUE_NAME = "work_queue"; 
    public static void main(String[] args) throws Exception { 
    
        //建立連線 
        Connection connection = ConnectionUtil.getConnection(); 
        
        // 建立頻道 
        Channel channel = connection.createChannel(); 
        
        // 宣告(建立)佇列 
        /**
         * 引數1:佇列名稱 
         * 引數2:是否定義持久化佇列 
         * 引數3:是否獨佔本次連線 
         * 引數4:是否在不使用的時候自動刪除佇列 
         * 引數5:佇列其它引數 
        */ 
        channel.queueDeclare(QUEUE_NAME, true, false, false, null); 
        for (int i = 1; i <= 30; i++) { 
            // 傳送資訊 
            String message = "你好;小兔子!work模式--" + i; 
            
            /**
             * 引數1:交換機名稱,如果沒有指定則使用預設Default Exchage 
             * 引數2:路由key,簡單模式可以傳遞佇列名稱 
             * 引數3:訊息其它屬性 
             * 引數4:訊息內容 
            */ 
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes()); 
            System.out.println("已傳送訊息:" + message); 
        }
        // 關閉資源 
        channel.close(); connection.close(); 
    } 
}

②消費者1

package com.itheima.rabbitmq.work; 
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(); 
        
        // 宣告(建立)佇列 
        /**
         * 引數1:佇列名稱 
         * 引數2:是否定義持久化佇列 
         * 引數3:是否獨佔本次連線 
         * 引數4:是否在不使用的時候自動刪除佇列 
         * 引數5:佇列其它引數 
        */ 
        channel.queueDeclare(Producer.QUEUE_NAME, true, false, false, null); 
        
        //一次只能接收並處理一個訊息 
        channel.basicQos(1); 
        
        //建立消費者;並設定訊息處理 
        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 { 
                try {
                
                    //路由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")); 
                    Thread.sleep(1000); 
                    
                    //確認訊息 
                    channel.basicAck(envelope.getDeliveryTag(), false); 
                } 
                catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } 
            } 
        };
        //監聽訊息 
        /**
         * 引數1:佇列名稱
         * 引數2:是否自動確認,設定為true為表示訊息接收到自動向mq回覆接收到了,mq接收到回覆會刪除訊息,設定為false則需要手動確認 
         * 引數3:訊息接收到後回撥 
        */ 
        channel.basicConsume(Producer.QUEUE_NAME, false, consumer); 
    } 
}

③消費者2

package com.itheima.rabbitmq.work; 
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(); 
        
        // 宣告(建立)佇列 
        /**
         * 引數1:佇列名稱 
         * 引數2:是否定義持久化佇列 
         * 引數3:是否獨佔本次連線 
         * 引數4:是否在不使用的時候自動刪除佇列 
         * 引數5:佇列其它引數 
        */ 
        channel.queueDeclare(Producer.QUEUE_NAME, true, false, false, null); 
        
        //一次只能接收並處理一個訊息 
        channel.basicQos(1); 
        
        //建立消費者;並設定訊息處理 
        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 { 
                try {
                    //路由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")); 
                    Thread.sleep(1000); 
                    
                    //確認訊息 
                    channel.basicAck(envelope.getDeliveryTag(), false); 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } 
            } 
        };
        //監聽訊息 
        /**
         * 引數1:佇列名稱 
         * 引數2:是否自動確認,設定為true為表示訊息接收到自動向mq回覆接收到了,mq接收到回覆會刪除訊息,設定為false則需要手動確認 
         * 引數3:訊息接收到後回撥 
        */ 
        channel.basicConsume(Producer.QUEUE_NAME, false, consumer); 
    } 
}

三、測試

啟動兩個消費者,然後再啟動生產者傳送訊息;到IDEA的兩個消費者對應的控制檯檢視是否競爭性的接收到訊息。

每日一學:你知道如何在 RabbitMQ 中實現 Work queues工作佇列模式嗎?

每日一學:你知道如何在 RabbitMQ 中實現 Work queues工作佇列模式嗎?

總結

在一個佇列中如果有多個消費者,那麼消費者之間對於同一個訊息的關係是 競爭的關係。

喜歡這篇文章的朋友們可以關注個人簡介中的公眾號

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69964492/viewspace-2767896/,如需轉載,請註明出處,否則將追究法律責任。

相關文章