RabbitMQ非官方教程(六)Topic交换

上一节教程中改进过程中,我们没有使用只能进行虚拟广播的fanout交换机,而是使用direct交换机,并有可能选择性地接收消息。尽管使用direct交换改进了我们的系统,但它仍然存在局限性,不能基于多个条件进行路由。

如果我们可能不仅要根据严重性订阅日志,还要根据发出日志的源订阅日志。为了实现这一点,我们需要学习更复杂的topic交换。

Topic交流

topic交换机的routingKey是单词列表,以点分隔。这些词可以是任何东西,但是通常它们指定与消息相关的某些功能。一些有效的路由关键示例:“ stock.usd.nyse ”,“ nyse.vmw ”,“ quick.orange.rabbit ”。路由密钥中可以包含任意多个单词,最多255个字节。绑定密钥也必须采用相同的形式。主题交换背后的逻辑类似于直接交换的逻辑,使用特定路由密钥发送的消息将被传递到所有使用匹配绑定密钥绑定的队列。绑定键有两个重要的特殊情况:

*:可以代替一个单词。

#:可以替代零个或多个单词。

RabbitMQ非官方教程(六)Topic交换_第1张图片

对于上面的匹配规则,我们举几个例子:

     路由键名称                   能匹配的队列
"quick.orange.rabbit":            Q1和Q2
"lazy.orange.elephant":           Q1和Q2
"quick.orange.fox":               Q1
"lazy.brown.fox":                 Q2
"lazy.pink.rabbit":               Q2
"quick.brown.fox":                都不匹配,被丢弃
"quick.orange.male.rabbit":       都不匹配,被丢弃
"lazy.orange.male.rabbit":        Q2

Topic Exchange

主题交换功能强大,可以像其他交流一样进行。

当队列用" # "绑定键绑定时,它将接收所有消息,而与路由键无关,就像在fanout交换中一样。

当在绑定中不使用特殊字符" * "和" # "时,主题交换的行为就像direct的一样。

接下来我们贴代码:

package com.mytest.rabbitMQ.Fifth;

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

public class EmitLogTopic {
    private static final String EXCHANGE_NAME = "topic_logs";

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

            String[] arg = {"kern.critical", "A critical kernel error"};
            String routingKey = getRouting(arg);
            String message = getMessage(arg);

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

    private static String getRouting(String[] strings) {
        if (strings.length < 1)
            return "anonymous.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) {
        if (strings.length == 0) return "";
        if (strings.length < startIndex) return "";
        StringBuilder words = new StringBuilder(strings[startIndex]);
        for (int i = startIndex + 1; i < strings.length; i++) {
            words.append(delimiter).append(strings[i]);
        }
        return words.toString();
    }
}

package com.mytest.rabbitMQ.Fifth;

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

public class ReceiveLogsTopic {
    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv) throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");

        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
        String queueName = channel.queueDeclare().getQueue();

        String[] arg = {"kern.*", "*.critical"};
        if (arg.length < 1) {
            System.err.println("Usage: ReceiveLogsTopic [binding_key]...");
            System.exit(1);
        }
        for (String bindingKey : arg) {
            channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
        }

        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 -> { });
    }
}

代码大体和上节教程差不多。

这是本节的demo代码地址:https://gitee.com/mjTree/javaDevelop/tree/master/testDemo

 

你可能感兴趣的:(rabbitmq)