rabbitmq(五)topic exchange

topic类型交换机的routingKey

向topic类型的交换机投递信息时设置的routingKey不能由单个标识符组成,必须由”.”分隔的若干个标识符组成(总长度不能大于255个字节)。下面第一个示例是非法的,第二个是合法的:

非法:

 //声明一个topic类型的交换机
 channel.exchangeDeclare(EXCHANGE_NAME, "topic");
 String routingKey="apple";
 channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes());

合法:

//声明一个topic类型的交换机
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
String routingKey="small.apple";
channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes());

routingKey的匹配规则

topic类型的交换机向队列投递信息和direct类型的交换机在逻辑上是相似的,只会将消息投递给绑定的routingKey和发布消息设置的routingKey相匹配的队列。与direct类型的交换机不同的是,topic类型的交换机在队列绑定routingKey时可以使用模式匹配:
* 匹配一个标识符
# 匹配0个或多个标识符

例如:
我们假设routingKey由3部分组成:<speed>.<colour>.<species>(分别为速度,颜色和物种)。队列Q1绑定的routingKey为”*.orange.*”,队列Q2绑定的routingKey为”*.*.rabbit” 和”lazy.#”。这样,队列Q1可以接收所有颜色为橙色(orange)的物种的消息,Q2则可以接收所有物种为兔子(rabbit)以及速度慢(lazy)的物种的消息。

 channel.exchangeDeclare(EXCHANGE_NAME, "topic");
 String routingKey=...;
 channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes());

下面举例说明投递消息设置的routingKey为不同值时,队列Q1和Q2的接收消息的情况:

  • quick.orange.rabbit
    消息会被转发到两个队列

  • lazy.orange.elephant
    消息也被转发到两个队列

  • quick.orange.fox
    只会被转发到Q1

  • lazy.brown.fox
    被转发到Q2

  • lazy.pink.rabbit
    虽然与Q2的绑定两个routingKey匹配,但是只会被转发到Q2一次

  • quick.brown.fox
    不匹配,被丢弃

  • orange
    一个标识符的routingKey违反了约定,不能与任何绑定键匹配,被丢弃

  • quick.orange.male.rabbit
    四个标识符违反了约定,被丢弃

  • lazy.orange.male.rabbit
    虽然是四个标识符,但可以与lazy.#匹配,从而转发至Q2

PS: 上面的例子来自rabbitmq的官方教程

可以看到,topic类型的交换机是非常强大和灵活的,我们可以通过topic类型的交换机来实现其他类型的交换机。例如,如果队列绑定的routingKey使用“#”可以实现fanout类型的交换机,routingKey不包含”#”和”.”则相当于direct类型的交换机。

示例

假设我们的系统有两个模块:web模块和admin模块。两个模块都有info、warning、error三种级别的日志。EmitLog随机发送web和admin模块三种级别的日志,PrintLog将两个模块的info和warning日志打到控制台,SaveLog将两个模块的error日志保存到文件。

EmitLog.java

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

import java.io.IOException;
import java.util.Random;

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

    private static final String[] LOG_MODULE_LEVEL = {"web.info", "web.warning", "web.error","admin.info", "admin.warning", "admin.error"};

    private static final Random random = new Random();

    public static void main(String[] args) {
        Connection connection = null;
        try {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("127.0.0.1");
            connection = factory.newConnection();
            Channel channel = connection.createChannel();
            channel.exchangeDeclare(EXCHANGE_NAME, "topic");

            String logLevel = getLogLevel();
            String log = "this is a log with the level:" + logLevel;
            channel.basicPublish(EXCHANGE_NAME, logLevel, null, log.getBytes());
            System.out.println("send the log:" + log);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (IOException e) {
                    // ignore this
                }
            }
        }
    }

    /**
     * 随机获取日志级别
     */
    private static String getLogLevel() {
        return LOG_MODULE_LEVEL[random.nextInt(3)];
    }

}

PrintLog.java

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

public class PrintLog {

    private static final String EXCHANGE_NAME = "topic_logs";

    private static final String[] ROUTING_KEYS = {"*.info", "*.warning"};

    public static void main(String[] args) {
        try {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("127.0.0.1");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();

            channel.exchangeDeclare(EXCHANGE_NAME, "topic");
            String queueName = channel.queueDeclare().getQueue();

            for (String routingKey : ROUTING_KEYS) {
                channel.queueBind(queueName, EXCHANGE_NAME, routingKey);
            }

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

            System.out.println("waiting for logs....");
            while (true) {
                QueueingConsumer.Delivery delivery = consumer.nextDelivery();
                String log = new String(delivery.getBody());
                String routingKey = delivery.getEnvelope().getRoutingKey();
                //打印日志
                System.out.println("receive the log:" + log);
                System.out.println("routingKey is:" + routingKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

SaveLog.java

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

public class SaveLog {

    private static final String EXCHANGE_NAME = "topic_logs";

    private static final String[] ROUTING_KEYS = {"*.error"};

    public static void main(String[] args) {
        try {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("127.0.0.1");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();

            channel.exchangeDeclare(EXCHANGE_NAME, "topic");
            String queueName = channel.queueDeclare().getQueue();

            for (String routingKey : ROUTING_KEYS) {
                channel.queueBind(queueName, EXCHANGE_NAME, routingKey);
            }

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

            System.out.println("waiting for logs....");
            while (true) {
                QueueingConsumer.Delivery delivery = consumer.nextDelivery();
                String log = new String(delivery.getBody());
                String routingKey = delivery.getEnvelope().getRoutingKey();

                //保存日志到文件(模拟)
                System.out.println("save the log:" + log);
                System.out.println("routingKey is:" + routingKey);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

参考资料:rabbitmq官方教程5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值