交换机

基本概念

发布订阅

发布订阅模式和之前两个模式的区别是允许将同一消息发送给多个消费者,实现方式是加入了exchange(交换机)

交换机

RabbitMQ 消息传递模型的核心思想是:生产者生产的消息从不会直接发送到队列,只能将消息发送到交换机(exchange),简单模式和工作模式使用的是默认交换机 AMQP default (空字符串表示)

临时队列

生成临时队列,当消费者断开和队列的连接时,队列就自动删除,示例代码如下:

String queueName = channel.queueDeclare().getQueue(); // 返回的是队列的随机名称

Fanout

扇出模式,也叫广播模式,此模式下交换机会将生产者发送的消息全都路由到每一个跟其绑定的队列,示意图如下:

在这里插入图片描述

代码实现(消费者 1):

 	    Channel channel = RabbitMqUtils.getChannel();
        // 声明一个交换机
        channel.exchangeDeclare("log", "fanout");
        // 声明一个临时队列
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机和队列
        channel.queueBind(queueName, "log", "");
        System.out.println("ReceiveLogs01等待接收消息,即将打印接收到的消息............");

        channel.basicConsume(queueName, true, ((consumerTag, message) -> {
            System.out.println("ReceiveLogs01打印接收到的消息:" + new String(message.getBody()));
        }),consumerTag -> {
            // 消费者被关闭时执行的操作
        });

代码实现(消费者 2):

  		Channel channel = RabbitMqUtils.getChannel();
        // 声明一个交换机
        channel.exchangeDeclare("log", "fanout");
        // 声明一个临时队列
        String queueName = channel.queueDeclare().getQueue();
        //绑定交换机和队列
        channel.queueBind(queueName, "log", "");
        System.out.println("ReceiveLogs02等待接收消息,即将打印接收到的消息............");

        channel.basicConsume(queueName, true, ((consumerTag, message) -> {
            System.out.println("ReceiveLogs02打印接收到的消息:" + new String(message.getBody()));
        }),consumerTag -> {
            // 消费者被关闭时执行的操作
        });

代码实现(生产者):

		Channel channel = RabbitMqUtils.getChannel();
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String message = scanner.next();
            channel.basicPublish("log", "", null, message.getBytes());
            System.out.println("生产者发出消息:" + message);
        }

Direct

路由模式,也叫直接模式,消息只去到它绑定的 routingKey 队列,如果 exchange 绑定的多个队列的 key 都相同,此时表现的作用就与 fanout 模式一致,示意图如下:

在这里插入图片描述

需求

生产者可以将日志消息发送到交换机,并根据不同的日志级别(路由键)将消息路由到相应的队列,消费者 1 可以处理 “info” 和 “warning” 级别的日志消息,而消费者 2 可以处理 “error” 级别的日志消息

代码实现

消费者 1:

        Channel channel = RabbitMqUtils.getChannel();
        // 声明一个交换机
        channel.exchangeDeclare("direct_log", BuiltinExchangeType.DIRECT);
        // 声明一个队列
        channel.queueDeclare("console", false, false, false, null);
        // 绑定
        channel.queueBind("console", "direct_log", "info");
        channel.queueBind("console", "direct_log", "warning");
        // 消费
        channel.basicConsume("console", true, (consumerTag, message) -> {
            System.out.println("ReceiveLogsDirect01打印接收到的消息:" + new String(message.getBody()));
        }, consumerTag -> {
            // 消费者被关闭时执行的操作
        });

消费者 2:

        Channel channel = RabbitMqUtils.getChannel();
        // 声明一个交换机
        channel.exchangeDeclare("direct_log", BuiltinExchangeType.DIRECT);
        // 声明一个队列
        channel.queueDeclare("disk", false, false, false, null);
        // 绑定
        channel.queueBind("disk", "direct_log", "error");
        // 消费
        channel.basicConsume("disk", true, (consumerTag, message) -> {
            System.out.println("ReceiveLogsDirect02打印接收到的消息:" + new String(message.getBody()));
        }, consumerTag -> {
            // 消费者被关闭时执行的操作
        });

生产者:

        Channel channel = RabbitMqUtils.getChannel();
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String message = scanner.next();
            // 指定不同 routingKey 通过交换机路由到不同的队列
            channel.basicPublish("direct_log", "error", null, message.getBytes());
            // channel.basicPublish("direct_log", "info", null, message.getBytes());
            // channel.basicPublish("direct_log", "warning", null, message.getBytes());

            System.out.println("生产者发出消息:" + message);
        }

Topic

Direct 的路由规则是精确匹配,而 Topic 交换机则支持通配符匹配,满足多个条件的话也只会被队列接收一次,其中 routingKey 必须是多个单词的组合,并且用 . 分割,与 Direct 对比更加的灵活

  • #:代表 0 个或多个单词.
  • *:代表 1 个单词
在这里插入图片描述

特殊情况:

  • 当一个队列绑定键是 #,那么这个队列将接收所有数据,作用与 fanout 模式相同
  • 如果队列绑定键当中没有 # 和 * 出现,作用与 direct 模式相同

代码实现

消费者 1:

        Channel channel = RabbitMqUtils.getChannel();

        // 声明交换机
        channel.exchangeDeclare("topic_logs", BuiltinExchangeType.TOPIC);
        // 声明队列
        channel.queueDeclare("Q1", false, false, false, null);
        // 绑定
        channel.queueBind("Q1", "topic_logs", "*.orange.*");
        System.out.println("ReceiveLogsTopic01等待接收消息..............");
        // 消费消息
        channel.basicConsume("Q1", true, ((consumerTag, message) -> {
            System.out.println("ReceiveLogsTopic01打印接收到的消息:" + new String(message.getBody()));
            System.out.println("routingKey为{}" + message.getEnvelope().getRoutingKey());
        }),consumerTag -> {
            // 消费者被关闭时执行的操作
        });

消费者 2:

        Channel channel = RabbitMqUtils.getChannel();

        // 声明交换机
        channel.exchangeDeclare("topic_logs", BuiltinExchangeType.TOPIC);
        // 声明队列
        channel.queueDeclare("Q2", false, false, false, null);
        // 绑定
        channel.queueBind("Q2", "topic_logs", "*.*.rabbit");
        channel.queueBind("Q2", "topic_logs", "lazy.#");
        System.out.println("ReceiveLogsTopic02等待接收消息..............");
        // 消费消息
        channel.basicConsume("Q2", true, ((consumerTag, message) -> {
            System.out.println("ReceiveLogsTopic02打印接收到的消息:" + new String(message.getBody()));
            System.out.println("routingKey为{}" + message.getEnvelope().getRoutingKey());
        }),consumerTag -> {
            // 消费者被关闭时执行的操作
        });

生产者:

        Channel channel = RabbitMqUtils.getChannel();

        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String routingKey = scanner.next();
            channel.basicPublish("topic_logs", routingKey, null, routingKey.getBytes());
            System.out.println(("生产者发出消息:" + routingKey)); // 这里为了方便演示把 routingKey 作为消息
        }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值