RabbitMQ路由選擇(五)

1、綁定(Bindings)
在上一篇博客中我們已經使用過綁定。類似下面的代碼:
channel.queueBind(queueName, EXCHANGE_NAME, "");
綁定表示轉發器與隊列之間的關係。我們也可以簡單的認爲:隊列對該轉發器上的消息感興趣。
綁定可以附帶一個額外的參數routingKey。爲了與避免basicPublish方法(發佈消息的方法)的參數混淆,我們準備把它稱作綁定鍵(binding key)。下面展示如何使用綁定鍵(binding key)來創建一個綁定:
channel.queueBind(queueName, EXCHANGE_NAME, "black");
綁定鍵的意義依賴於轉發器的類型。對於fanout類型,忽略此參數。
2、直接轉發(Direct exchange)
上一篇的日誌系統廣播所有的消息給所有的消費者。我們希望可以對其擴展,來允許根據日誌的嚴重性進行過濾日誌。例如:我們可能希望把致命類型的錯誤寫入硬盤,而不把硬盤空間浪費在警告或者消息類型的日誌上。
之前我們使用fanout類型的轉發器,但是並沒有給我們帶來更多的靈活性:僅僅可以愚蠢的轉發。
我們將會使用direct類型的轉發器進行替代。direct類型的轉發器背後的路由轉發算法很簡單:消息會被推送至綁定鍵(binding key)和消息發佈附帶的選擇鍵(routing key)完全匹配的隊列。
圖解:

上圖,我們可以看到direct類型的轉發器與兩個隊列綁定。第一個隊列與綁定鍵orange綁定,第二個隊列與轉發器間有兩個綁定,一個與綁定鍵black綁定,另一個與green綁定鍵綁定。
這樣的話,當一個消息附帶一個選擇鍵(routing key) orange發佈至轉發器將會被導向到隊列Q1。消息附帶一個選擇鍵(routing key)black或者green將會被導向到Q2.所有的其他的消息將會被丟棄。

3、多重綁定(multiple bindings)

使用一個綁定鍵(binding key)綁定多個隊列是完全合法的。如上圖,一個附帶選擇鍵(routing key)的消息將會被轉發到Q1和Q2。

4、發送日誌(Emittinglogs)

我們準備將這種模式用於我們的日誌系統。我們將消息發送到direct類型的轉發器而不是fanout類型。我們將把日誌的嚴重性作爲選擇鍵(routing key)。這樣的話,接收程序可以根據嚴重性來選擇接收。我們首先關注發送日誌的代碼:

像以前一樣,我們需要先創建一個轉發器:

channel.exchangeDeclare(EXCHANGE_NAME,"direct");

然後我們準備發送一條消息:

channel.basicPublish(EXCHANGE_NAME,severity, null, message.getBytes());

爲了簡化代碼,我們假定‘severity’是‘info’,‘warning’,‘error’中的一個。

5、訂閱

接收消息的代碼和前面的博客的中類似,只有一點不同:我們給我們所感興趣的嚴重性類型的日誌創建一個綁定。

StringqueueName = channel.queueDeclare().getQueue();

for(Stringseverity : argv)

{

channel.queueBind(queueName, EXCHANGE_NAME, severity);

}

6、完整的實例

參考代碼如下:

package wenjie.route;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeoutException;

/**
 * Created by Gongwenjie on 2018-05-08
 */
public class EmitLogDirect
{

    private static final String EXCHANGE_NAME = "ex_logs_direct";
    private static final String[] SEVERITIES = { "info", "warning", "error" };

    public static void main(String[] argv) throws java.io.IOException,TimeoutException
    {
        // 創建連接和頻道
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        // 聲明轉發器的類型
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");

        //發送6條消息
        for (int i = 0; i < 6; i++)
        {
            String severity = getSeverity();
            String message = severity + "_log :" + UUID.randomUUID().toString();
            // 發佈消息至轉發器,指定routingkey
            channel.basicPublish(EXCHANGE_NAME, severity, null, message
                    .getBytes());
            System.out.println(" [x] Sent '" + message + "'");
        }

        channel.close();
        connection.close();
    }

    /**
     * 隨機產生一種日誌類型
     *
     * @return
     */
    private static String getSeverity()
    {
        Random random = new Random();
        int ranVal = random.nextInt(3);
        return SEVERITIES[ranVal];
    }
}

package wenjie.route;

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

import java.util.Random;
import java.util.concurrent.TimeoutException;

/**
 * Created by Gongwenjie on 2018-05-08
 */
public class ReceiveLogsDirect
{

    private static final String EXCHANGE_NAME = "ex_logs_direct";
    private static final String[] SEVERITIES = { "info", "warning", "error" };

    public static void main(String[] argv) throws java.io.IOException,TimeoutException,
            java.lang.InterruptedException
    {
        // 創建連接和頻道
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        // 聲明direct類型轉發器
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");

        String queueName = channel.queueDeclare().getQueue();
        String severity = getSeverity();
        // 指定binding_key
        channel.queueBind(queueName, EXCHANGE_NAME, severity);
        System.out.println(" [*] Waiting for "+severity+" logs. To exit press CTRL+C");

        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(queueName, true, consumer);

        while (true)
        {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");
        }
    }

    /**
     * 隨機產生一種日誌類型
     *
     * @return
     */
    private static String getSeverity()
    {
        Random random = new Random();
        int ranVal = random.nextInt(3);
        return SEVERITIES[ranVal];
    }
}

輸出結果如下:

 [x] Sent 'warning_log :46371a9d-bce3-43a7-aacd-69cf4f6cf392'
 [x] Sent 'error_log :98a6cb10-6067-4032-bd68-00fe55ec370b'
 [x] Sent 'info_log :6c0487e7-7ff8-4b5a-a238-00dbd1d560e6'
 [x] Sent 'error_log :b7df14b6-4095-4480-88e9-d0e80466fb5e'
 [x] Sent 'warning_log :f9201494-65c7-444b-b7b3-5c9deb24d730'
 [x] Sent 'warning_log :596dbaa1-164a-453c-9286-681084bab986'

Connected to the target VM, address: '127.0.0.1:52935', transport: 'socket'
 [*] Waiting for warning logs. To exit press CTRL+C
 [x] Received 'warning_log :46371a9d-bce3-43a7-aacd-69cf4f6cf392'
 [x] Received 'warning_log :f9201494-65c7-444b-b7b3-5c9deb24d730'
 [x] Received 'warning_log :596dbaa1-164a-453c-9286-681084bab986'

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