RabbitMQ非官方教程(五)路由

上一個教程中,我們構建一個fanout類型的交換機,它能夠向許多接收者廣播消息。在本教程中我們將學習direct類型的交換機,向其中添加功能然後使僅訂閱消息的子集成爲可能。例:我們將只能將帶有error標記的消息定向到A隊列,其他標誌的消息定向到B隊列。

爲了能夠實現上面的功能,direct類型的交換機帶有一個參數來實現。routingKey被稱爲綁定鍵,綁定密鑰的含義取決於交換類型。我們之前使用的fanout交換隻是忽略了它的價值。

// 這是fanout類型交換機綁定隊列的代碼聲明
channel.queueBind(queueName, EXCHANGE_NAME, "");

// 這是direct類型交換機綁定隊列的代碼聲明
channel.queueBind(queueName, EXCHANGE_NAME, routingKey);

爲什麼交換機存在direct類型的,fanout不夠用嗎?

上一教程中的Demo中我們將所有消息廣播給所有使用者,我們想要擴展它以允許根據郵件的嚴重性過濾郵件。例如,我們可能希望將日誌消息寫入磁盤的程序僅接收嚴重錯誤,而不會在警告或信息日誌消息上浪費磁盤空間。我們使用的是fanout交換,這種交換並沒有給我們帶來太大的靈活性,因爲它只能進行無意識的廣播。這裏我們將使用direct交換,direct交換背後的路由算法很簡單,消息進入其綁定密鑰與消息的路由密鑰完全匹配的隊列 。

我們舉個簡單例子的僞代碼:

// 定義一個direct交換機和A、B兩個隊列
channel.exchangeDeclare(exchange='first', type='direct')
channel.queueDeclare(queue='A')
channel.queueDeclare(queue='B')


// A隊列使用a綁定鍵,B隊列使用b綁定鍵
channel.queueBind(exchange='first', queue='A', routingKey='error')
channel.queueBind(exchange='first', queue='B', routingKey='warning')


// 發送消息
channel.basicPublish(exchange='first', routingKey='error', body='Hello World!')
channel.basicPublish(exchange='first', routingKey='warning', body='Hello World!')

這個時候我只需把error隊列的消息寫入磁盤便於我們去查看項目哪裏出錯,而warning這些信息不太重要,不需要存在磁盤就在B隊列放着讓編譯器在控制檯打印出來就行了。這種方法可以減少磁盤的不必要的存儲消耗和讀寫性能。

接下來我們貼具體代碼:

這是本節的demo代碼地址:https://gitee.com/mjTree/javaDevelop/tree/master/testDemo

package com.mytest.rabbitMQ.Fourth;

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

public class EmitLogDirect {
    private static final String EXCHANGE_NAME = "direct_logs";

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);

            // 模擬命令行提供參數
            //String[] arg = {};
            //String[] arg = {"warning", "nothing"};
            String[] arg = {"error", "Run or it will explode."};
            String severity = getSeverity(arg);
            String message = getMessage(arg);

            channel.basicPublish(EXCHANGE_NAME, severity,
                    null, message.getBytes("UTF-8"));
            System.out.println(" [x] Sent '" + severity + "':'" + message + "'");
        }
    }

    private static String getSeverity(String[] strings) {
        if (strings.length < 1)
            return "info";
        return strings[0];
    }

    private static String getMessage(String[] strings) {
        if (strings.length < 2)
            return "Hello World!";
        return joinStrings(strings, " ", 1);
    }

    private static String joinStrings(String[] strings, String delimiter, int startIndex) {
        int length = strings.length;
        if (length == 0) return "";
        if (length <= startIndex) return "";
        StringBuilder words = new StringBuilder(strings[startIndex]);
        for (int i = startIndex + 1; i < length; i++) {
            words.append(delimiter).append(strings[i]);
        }
        return words.toString();
    }
}
package com.mytest.rabbitMQ.Fourth;

import com.rabbitmq.client.*;

public class ReceiveLogsDirect {
    private static final String EXCHANGE_NAME = "direct_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, BuiltinExchangeType.DIRECT);
        String queueName = channel.queueDeclare().getQueue();   // 隨機生成隊列
        String queueName1 = channel.queueDeclare().getQueue();

        // 模擬命令行提供參數
        //String[] arg = {};
        String[] arg = {"info", "warning", "error"};
        if (arg.length < 1) {
            System.err.println("Usage: ReceiveLogsDirect [info] [warning] [error]");
            System.exit(1);
        }

        // 交換機和隊列綁定
        channel.queueBind(queueName, EXCHANGE_NAME, arg[2]);    // 把error綁在第一個隊列
        // info和warning綁在第二個隊列中
        channel.queueBind(queueName1, EXCHANGE_NAME, arg[0]);
        channel.queueBind(queueName1, EXCHANGE_NAME, arg[1]);

        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" +
                    delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
        };
        channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
        channel.basicConsume(queueName1, true, deliverCallback, consumerTag -> { });
    }
}

先執行執行ReceiveLogsDirect,然後再對EmitLogDirect執行三次生成三個標誌消息,三次執行過程的arg都要不一樣,分別對arg註釋執行。

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