rabbitmq-Topic exchange(主題交換器)

Topic exchange

消息發送到topic exchange(主題交換器)不能具有任意的routing_key(路由鍵),它必須是一系列的單詞,使用點號.分隔。這些單詞可以是任意的,但是經常定義了與消息相關的特性。一些有效的路由鍵示例:"stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit"。路由鍵中的字可以任意多個,最多255個字節。

綁定的鍵必須是相同的形式。主題交換器(topic exchange)背後的邏輯和直接交換器(direct exchange)的邏輯是相似的,一個帶特別路由鍵的消息會被髮送到與之路由鍵匹配的隊列。對於路由鍵有兩種重要的特殊情況:

1、*代替一個單詞

2、#代替零個或多個單詞

使用以下例子能很容易地解釋以上情況

 

在這個例子裏,我們會給所有描述的動物發送消息。這些消息使用三個單詞(兩個點號)組成的路由鍵進行發送。第一個單詞描述速度,第二個單詞描述顏色,第三個代表種類:

"<speed>.<colour>.<species>"

我們創建三個綁定,Q1綁定”*.orange.*”,Q2綁定”*.*.rabbit”和”lazy.#”。

這些綁定可以通過以下兩點概況:

1、       Q1對橘黃色的動物感興趣

2、       Q2想要傾聽任何關於rabbit,任何關於lazy 動物的東西。

 

路由鍵設置爲”quick.orange.rabbit”的消息將被髮送到兩個隊列。消息”lazy.orange.elephant”也將被髮送到兩個隊列。另一方面,”quick.orange.fox”將被髮送到Q1隊列,“lazy.brown.fox”只會被髮送到Q2對列。”lazy.pink.rabbit”將只會被髮送到Q2隊列一次,雖然它匹配兩個綁定。”quick.brown.fox”不能匹配任何綁定,將會被丟棄。

如果我們破壞規則,發送1個或4個單詞的消息會發送什麼,比如”orange”或者”quick.orange.male.rabbit”?很好,這些消息不會匹配任何的綁定,將會丟失。

另一方面,”lazy.orange.male.rabbit”,雖然有四個單詞,但是它匹配了最後的綁定(lazy.#),會被髮送到第二個隊列。

Topic exchange功能強大,可以做其他交換器做的事情。

當一個對列使用#作爲綁定鍵,它就可以接受任何消息,無視路由鍵,就像fanout exchange(扇形交換器)。

當對列在綁定鍵中不使用*或者#,那麼topic exchange(主題交換器)就像一個direct exchange(直接交換器)。

 

實例,以下消費者實例不是同時啓動,是分別運行,每次只運行一個消費者實例

生產者

發送消息:

Send quick.orange.rabbit:Hello,RabbitMq1
Send lazy.orange.elephant:Hello,RabbitMq2
Send quick.orange.fox:Hello,RabbitMq3
Send lazy.brown.fox:Hello,RabbitMq4
Send lazy.pink.rabbit:Hello,RabbitMq5
Send quick.brown.fox:Hello,RabbitMq6

package com.enjoy.testrabbitmq;

import com.enjoy.common.RabbitmqConnection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class TestProducerTopic {
    public final static String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] args)
            throws IOException, TimeoutException {
        /* 創建連接,連接到RabbitMQ*/
        Connection connection = RabbitmqConnection.getConnection();

        /*創建信道*/
        Channel channel = connection.createChannel();
        /*創建topic交換器*/
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");

        /*日誌消息級別,作爲路由鍵使用*/
        String[] routekeys = {
                "quick.orange.rabbit"//匹配*.orange.*
                ,"lazy.orange.elephant"//匹配lazy.#,
                ,"quick.orange.fox"
                ,"lazy.brown.fox"
                ,"lazy.pink.rabbit"
                ,"quick.brown.fox"};
        for(int i=0;i<routekeys.length;i++){
            String routekey = routekeys[i];
            String msg = "Hello,RabbitMq"+(i+1);
            /*發佈消息,需要參數:交換器,路由鍵,其中以日誌消息級別爲路由鍵*/
            channel.basicPublish(EXCHANGE_NAME,routekey,null,
                    msg.getBytes());
            System.out.println("Send "+routekey+":"+msg);
        }
        channel.close();
        connection.close();

    }
}

消費者A

接受到消息:

Received[quick.orange.rabbit]Hello,RabbitMq1
Received[lazy.orange.elephant]Hello,RabbitMq2
Received[quick.orange.fox]Hello,RabbitMq3

package com.enjoy.testrabbitmq;

import com.enjoy.common.RabbitmqConnection;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**

 *類說明:普通的消費者
 */
public class TestConsumerTopicA {

    public static void main(String[] argv)
            throws IOException, TimeoutException {
        // 打開連接和創建頻道,與發送端一樣
        Connection connection = RabbitmqConnection.getConnection();

        final Channel channel = connection.createChannel();
        channel.exchangeDeclare(TestProducerTopic.EXCHANGE_NAME,
                "topic");

        /*聲明一個隊列*/
        String queueName = "orange";
        channel.queueDeclare(queueName,false,false,
                false,null);

        /*綁定,將隊列和交換器通過路由鍵進行綁定*/
        String routekey = "*.orange.*";
        channel.queueBind(queueName, TestProducerTopic.EXCHANGE_NAME,routekey);

        System.out.println("waiting for message........");

        /*聲明瞭一個消費者*/
        final Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException {
                String message = new String(body, "UTF-8");
                System.out.println("Received["+envelope.getRoutingKey()
                        +"]"+message);
            }
        };
        /*消費者正式開始在指定隊列上消費消息*/
        channel.basicConsume(queueName,true,consumer);
    }

}

消費者B

接收消息:

Received[quick.orange.rabbit]Hello,RabbitMq1
Received[lazy.pink.rabbit]Hello,RabbitMq5
 

package com.enjoy.testrabbitmq;

import com.enjoy.common.RabbitmqConnection;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**

 *類說明:普通的消費者
 */
public class TestConsumerTopicB {

    public static void main(String[] argv)
            throws IOException, TimeoutException {
        // 打開連接和創建頻道,與發送端一樣
        Connection connection = RabbitmqConnection.getConnection();

        final Channel channel = connection.createChannel();
        channel.exchangeDeclare(TestProducerTopic.EXCHANGE_NAME,
                "topic");

        /*聲明一個隊列*/
        String queueName = "rabbit";
        channel.queueDeclare(queueName,false,false,
                false,null);

        /*綁定,將隊列和交換器通過路由鍵進行綁定*/
        String bindKey = "*.*.rabbit";
        channel.queueBind(queueName, TestProducerTopic.EXCHANGE_NAME,bindKey);

        System.out.println("waiting for message........");

        /*聲明瞭一個消費者*/
        final Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException {
                String message = new String(body, "UTF-8");
                System.out.println("Received["+envelope.getRoutingKey()
                        +"]"+message);
            }
        };
        /*消費者正式開始在指定隊列上消費消息*/
        channel.basicConsume(queueName,true,consumer);
    }

}

消費者C

Received[lazy.orange.elephant]Hello,RabbitMq2
Received[lazy.brown.fox]Hello,RabbitMq4
Received[lazy.pink.rabbit]Hello,RabbitMq5

package com.enjoy.testrabbitmq;

import com.enjoy.common.RabbitmqConnection;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**

 *類說明:普通的消費者
 */
public class TestConsumerTopicC {

    public static void main(String[] argv)
            throws IOException, TimeoutException {
        // 打開連接和創建頻道,與發送端一樣
        Connection connection = RabbitmqConnection.getConnection();

        final Channel channel = connection.createChannel();
        channel.exchangeDeclare(TestProducerTopic.EXCHANGE_NAME,
                "topic");

        /*聲明一個隊列*/
        String queueName = "lazy";
        channel.queueDeclare(queueName,false,false,
                false,null);

        /*綁定,將隊列和交換器通過路由鍵進行綁定*/
        String bindKey = "lazy.#";
        channel.queueBind(queueName, TestProducerTopic.EXCHANGE_NAME,bindKey);

        System.out.println("waiting for message........");

        /*聲明瞭一個消費者*/
        final Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException {
                String message = new String(body, "UTF-8");
                System.out.println("Received["+envelope.getRoutingKey()
                        +"]"+message);
            }
        };
        /*消費者正式開始在指定隊列上消費消息*/
        channel.basicConsume(queueName,true,consumer);
    }

}

 

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