RabbitMQ 路由(Routing)模式示例

总结自:BV15k4y1k7Ep

模式说明

消费订阅模式相比,路由模式特点:

  • 交换机的类型为 Direct。
  • 队列与交换机绑定时,要指定一个Routing key(路由 key)。
  • 消息的发送方在向 Exchange 发送消息时,也必须指定消息的Routing key
  • Exchange 不再把消息交给每一个绑定的队列,而是根据消息的Routing key进行判断,只有队列的Routing key与消息的 Routing key完全一致,才会接收到消息。

1556029284397

图解:

  • P:生产者,向 Exchange 发送消息,发送消息时,会指定一个 routing key。
  • X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与 routing key 完全匹配的队列
  • C1:消费者,其所在队列指定了需要 routing key 为 error 的消息
  • C2:消费者,其所在队列指定了需要 routing key 为 info、error、warning 的消息

代码

在编码上与Publish/Subscribe模式的区别是交换机的类型为 Direct,还有队列绑定交换机的时候需要指定 routing key。

1)生产者

package com.zhangmingge.rabbitmq.routing;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.zhangmingge.rabbitmq.ConnectionUtil;

/**
 * 路由模式的交换机类型为:direct
 */
public class Producer {

    // 交换机名称
    static final String DIRECT_EXCHANGE = "direct_exchange";
    // 队列名称
    static final String DIRECT_QUEUE_INSERT = "direct_queue_insert";
    // 队列名称
    static final String DIRECT_QUEUE_UPDATE = "direct_queue_update";

    public static void main(String[] args) throws Exception {

        // 创建连接
        Connection connection = ConnectionUtil.getConnection();

        // 创建频道
        Channel channel = connection.createChannel();

        /*
         * 声明交换机
         * 参数 1:交换机名称
         * 参数 2:交换机类型,fanout、topic、direct、headers
         */
        channel.exchangeDeclare(DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);

        // 声明(创建)队列
        /*
         * 参数 1:队列名称
         * 参数 2:是否定义持久化队列
         * 参数 3:是否独占本次连接
         * 参数 4:是否在不使用的时候自动删除队列
         * 参数 5:队列其它参数
         */
        channel.queueDeclare(DIRECT_QUEUE_INSERT, true, false, false, null);
        channel.queueDeclare(DIRECT_QUEUE_UPDATE, true, false, false, null);

        // 队列绑定交换机
        channel.queueBind(DIRECT_QUEUE_INSERT, DIRECT_EXCHANGE, "insert");
        channel.queueBind(DIRECT_QUEUE_UPDATE, DIRECT_EXCHANGE, "update");

        // 发送信息
        String message = "新增了商品。路由模式;routing key 为 insert ";
        /*
         * 参数 1:交换机名称,如果没有指定则使用默认 Default Exchange
         * 参数 2:路由 key,简单模式可以传递队列名称
         * 参数 3:消息其它属性
         * 参数 4:消息内容
         */
        channel.basicPublish(DIRECT_EXCHANGE, "insert", null, message.getBytes());
        System.out.println("已发送消息:" + message);

        // 发送信息
        message = "修改了商品。路由模式;routing key 为 update";
        /*
         * 参数 1:交换机名称,如果没有指定则使用默认 Default Exchange
         * 参数 2:路由 key,简单模式可以传递队列名称
         * 参数 3:消息其它属性
         * 参数 4:消息内容
         */
        channel.basicPublish(DIRECT_EXCHANGE, "update", null, message.getBytes());
        System.out.println("已发送消息:" + message);

        // 关闭资源
        channel.close();
        connection.close();
    }
}

注意其中声明的交换机的类型为 Direct:

channel.exchangeDeclare(DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);

队列绑定到交换机时指定了 routing key:

// 队列绑定交换机
channel.queueBind(DIRECT_QUEUE_INSERT, DIRECT_EXCHANGE, "insert");
channel.queueBind(DIRECT_QUEUE_UPDATE, DIRECT_EXCHANGE, "update");

发送消息时同样指定了 routing key:

/*
 * 参数 1:交换机名称,如果没有指定则使用默认 Default Exchange
 * 参数 2:路由 key,简单模式可以传递队列名称
 * 参数 3:消息其它属性
 * 参数 4:消息内容
 */
channel.basicPublish(DIRECT_EXCHANGE, "update", null, message.getBytes());

2)消费者 1

package com.zhangmingge.rabbitmq.routing;

import com.rabbitmq.client.*;
import com.zhangmingge.rabbitmq.ConnectionUtil;

import java.io.IOException;

public class Consumer1 {

    public static void main(String[] args) throws Exception {
        Connection connection = ConnectionUtil.getConnection();

        // 创建频道
        Channel channel = connection.createChannel();

        // 声明交换机
        channel.exchangeDeclare(Producer.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);

        // 声明(创建)队列
        /*
         * 参数 1:队列名称
         * 参数 2:是否定义持久化队列
         * 参数 3:是否独占本次连接
         * 参数 4:是否在不使用的时候自动删除队列
         * 参数 5:队列其它参数
         */
        channel.queueDeclare(Producer.DIRECT_QUEUE_INSERT, true, false, false, null);

        // 队列绑定交换机
        channel.queueBind(Producer.DIRECT_QUEUE_INSERT, Producer.DIRECT_EXCHANGE, "insert");

        // 创建消费者;并设置消息处理
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            /*
             * consumerTag 消息者标签,在 channel.basicConsume 时候可以指定
             * envelope 消息包的内容,可从中获取消息 id,消息 routingkey,交换机,消息和重传标志 (收到消息失败后是否需要重新发送)
             * properties 属性信息
             * body 消息
             */
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException {
                // 路由 key
                System.out.println("路由 key 为:" + envelope.getRoutingKey());
                // 交换机
                System.out.println("交换机为:" + envelope.getExchange());
                // 消息 id
                System.out.println("消息 id 为:" + envelope.getDeliveryTag());
                // 收到的消息
                System.out.println("消费者 1-接收到的消息为:" + new String(body, "utf-8"));
            }
        };
        // 监听消息
        /*
         * 参数 1:队列名称
         * 参数 2:是否自动确认,设置为 true 为表示消息接收到自动向 mq 回复接收到了,mq 接收到回复会删除消息,设置为 false 则需要手动确认
         * 参数 3:消息接收到后回调
         */
        channel.basicConsume(Producer.DIRECT_QUEUE_INSERT, true, consumer);
    }
}

注意其中声明的交换机的类型为 Direct:

channel.exchangeDeclare(Producer.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);

队列绑定到交换机时指定了 routing key:

channel.queueBind(Producer.DIRECT_QUEUE_INSERT, Producer.DIRECT_EXCHANGE, "insert");

3)消费者 2

消费者 2 和消费者 1 只有日志内容和所绑定队列不同,其他没有区别。

package com.zhangmingge.rabbitmq.routing;

import com.rabbitmq.client.*;
import com.zhangmingge.rabbitmq.ConnectionUtil;

import java.io.IOException;

public class Consumer2 {

    public static void main(String[] args) throws Exception {
        ...
        // 声明(创建)队列
        channel.queueDeclare(Producer.DIRECT_QUEUE_UPDATE, true, false, false, null);

        // 队列绑定交换机
        channel.queueBind(Producer.DIRECT_QUEUE_UPDATE, Producer.DIRECT_EXCHANGE, "update");

        // 创建消费者;并设置消息处理
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException {
                ...
                System.out.println("消费者 2-接收到的消息为:" + new String(body, "utf-8"));
            }
        };
        // 监听消息
        channel.basicConsume(Producer.DIRECT_QUEUE_UPDATE, true, consumer);
    }
}

测试

启动所有消费者,然后使用生产者发送消息;在消费者对应的控制台可以查看到生产者发送对应 routing key 对应队列的消息;到达按照需要接收的效果。

在执行完测试代码后,其实到 RabbitMQ 的管理后台找到Exchanges选项卡,点击 direct_exchange 的交换机,可以查看到如下的绑定:

1556031175744

小结

Routing 模式的交换机类型为 Direct,要求队列在绑定交换机时要指定 routing key,消息会转发到符合 routing key 的队列。

posted @ 2024-10-19 11:38  Higurashi-kagome  阅读(28)  评论(0编辑  收藏  举报