rabbitmq-Topic exchange(主题交换器)

Topic exchange

消息发送到topic exchange(主题交换器)不能具有任意的routing_key(路由键),它必须是一系列的单词,使用点号.分隔。这些单词可以是任意的,但是经常定义了与消息相关的特性。一些有效的路由键示例:"stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit"。路由键中的字可以任意多个,最多255个字节。

绑定的键必须是相同的形式。主题交换器(topic exchange)背后的逻辑和直接交换器(direct exchange)的逻辑是相似的,一个带特别路由键的消息会被发送到与之路由键匹配的队列。对于路由键有两种重要的特殊情况:

1、*代替一个单词

2、#代替零个或多个单词

使用以下例子能很容易地解释以上情况

rabbitmq-Topic exchange(主题交换器)_第1张图片

 

在这个例子里,我们会给所有描述的动物发送消息。这些消息使用三个单词(两个点号)组成的路由键进行发送。第一个单词描述速度,第二个单词描述颜色,第三个代表种类:

".."

我们创建三个绑定,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

消费者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);
    }

}

 

你可能感兴趣的:(Java,RabbitMQ)