RabbitMQ交换机

交换机

概念

RabbitMQ 消息传递模型的核心思想是:生产者生产的消息从不会直接发送到队列。实际上,通常生产者甚至都不知道这些消息传递到了哪些队列中。

相反,生产者只能将消息发送到交换机(exchange),**交换机工作的内容非常简单,一方面接收来自生产者的消息,另一方面将他们推入队列。交换机必须明确知道如何处理收到的消息。**是应该把这些消息放到特定队列还是说把他们放到许多队列中还是说应该丢弃他们。这就得由交换机的类型来决定。

类型

总共有以下类型:

直接(direct,路由),主题(topic),标题(headers),扇出(fanout,发布订阅模式)

bindings

绑定时交换机和队列之间的桥梁关系。也可以这么理解:队列只对它绑定的交换机的消息感兴趣。绑定用参数:routingKey来表示也可称该参数为 binding key,创建绑定我们用代码:channelQueueBind(queueName, EXCHANGE_NAME, "routingKey");绑定之后的意义由其交换类型决定。

Fanout

概念

Fanout 这种类型非常简单。它是将接收到的所有消息广播到它知道的所有队列中。系统中默认有些 exchange 类型。

生产者
java 复制代码
package com.my.rabbitmq.five;
​
import com.my.utils.RabbitMQUtils;
import com.rabbitmq.client.Channel;
​
import java.util.Scanner;
​
/**
 * @author 林允
 * @version 1.0
 * @description: TODO
 * @date 2023/11/29 15:33
 */
// 发送消息
public class EmitLog {
​
    public static final String Exchange_NAME = "logs";
​
    public static void main(String[] args) throws Exception{
        Channel channel = RabbitMQUtils.getChannel();
        channel.exchangeDeclare(Exchange_NAME, "fanout");
​
        Scanner sc = new Scanner(System.in);
​
        while (sc.hasNext()){
            String message = sc.next();
            channel.basicPublish(Exchange_NAME, "", null, message.getBytes("UTF-8"));
            System.out.println("生产者发出消息" + message);
        }
    }
​
}
消费者
java 复制代码
package com.my.rabbitmq.five;
​
import com.my.utils.RabbitMQUtils;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
​
/**
 * @author 林允
 * @version 1.0
 * @description: TODO
 * @date 2023/11/29 15:34
 */
​
// 消息接收
public class ReceiveLogs01 {
​
    // 交换机的名称
    public static final String EXCHANGE_NAME = "logs";
​
    public static void main(String[] args) throws Exception{
        Channel channel = RabbitMQUtils.getChannel();
        // 声明一个交换机
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        // 声明一个队列 临时队列
        /**
         * 生产一个临时队列,队列的名称是随机的
         * 当消费者断开与队列的连接的时候 队列就自动删除
         */
        String queueName = channel.queueDeclare().getQueue();
        /**
         * 绑定交换机与队列
         */
        channel.queueBind(queueName, EXCHANGE_NAME, "");
        System.out.println("等待接收消息,把接收到的消息打印在屏幕上....");
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("接收消息:" + new String(message.getBody(), "UTF-8"));
        };
        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println("接收失败");
        };
        channel.basicConsume(queueName, true, deliverCallback, cancelCallback);
    }
​
}
java 复制代码
package com.my.rabbitmq.five;
​
import com.my.utils.RabbitMQUtils;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
​
/**
 * @author 林允
 * @version 1.0
 * @description: TODO
 * @date 2023/11/29 16:01
 */
​
// 消息接收
public class ReceiveLogs02 {
​
    public static final String EXCHANGE_NAME = "logs";
​
    public static void main(String[] args) throws Exception {
        // 通过连接获取信道
        Channel channel = RabbitMQUtils.getChannel();
        // 声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        // 声明队列
        String queue = channel.queueDeclare().getQueue();
        // 将队列和交换机进行绑定
        channel.queueBind(queue, EXCHANGE_NAME, "");
        System.out.println("ReceiveLogs02 等待接收消息,把接收到的消息打印在屏幕上....");
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("接收到消息:" + new String(message.getBody(), "UTF-8"));
        };
​
        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println("接收失败" + consumerTag);
        };
        channel.basicConsume(queue, true, deliverCallback, cancelCallback);;
​
    }
​
}

Direct

Fanout这种交换类型并不能给我们带来很大的灵活性 - 它只能进行无意识的广播,在这里我们将使用direct 这种类型来进行替换,这种类型的工作方式是,消息只去到它绑定的routingKey队列中去。

如果与direct交换机绑定的多个队列的 routingKey 如果都相同 ,在这种情况下虽然绑定类型是 direct ,但是它表现的就和 fanout 差不多了

routingKey 相同 --> fanout交换机

routingKey 不相同 --> direct交换机

Topics

尽管使用 direct 交换机根据 routingKey 发到指定的队列,但是它仍然存在局限性,比如所我们只想接收 info.base 的消息,但是只要 routingKey 是 info 的就会全部接收,这个时候就只能使用topic类型

要求

发送到类型是 topic 交换机的消息的 routingKey 不能随意写,必须满足一定的要求,它必须是一个单词列表,以点号分隔开。这些单词可以是任意单词,比如说:"stock.usd.nyse","nyse.vmw","quick.orange.rabbit"这种类型的。当然这个单词列表最多不能超过 255 个字节。

在这个规则列表中,其中有两个替换符是需要注意的

*(星号)可以代替一个单词

#(井号)可以替代零个或多个单词

当队列绑定关系是下列这种情况时需要注意

当一个队列绑定键是 # ,那么这个队列将接收所有数据,就有点像 fanout

如果队列绑定键中没有 # 和 * 出现,那么该队列绑定的类型就是 direct

消费者
java 复制代码
package com.my.rabbitmq.six;
​
import com.my.utils.RabbitMQUtils;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
​
/**
 * @author 林允
 * @version 1.0
 * @description: TODO
 * @date 2023/11/29 16:28
 */
// 声明主题交换机及相关队列
// 消费者C1
public class ReceiveLogsTopic01 {
​
    // 交换机的名称
    public static final String EXCHANGE_NAME = "topic_logs";
​
    // 接收消息
    public static void main(String[] args) throws Exception{
        Channel channel = RabbitMQUtils.getChannel();
        // 声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
        // 声明队列
        String queueName = "Q1";
        channel.queueDeclare(queueName, false, false, false, null);
        channel.queueBind(queueName, EXCHANGE_NAME, "*.orange.*");
        System.out.println("等待接收消息");
​
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println(new String(message.getBody(), "UTF-8"));
            System.out.println("接收队列:" + queueName + " 绑定键:" + message.getEnvelope().getRoutingKey());
        };
        // 接收消息
        channel.basicConsume(queueName, true, deliverCallback, consumerTag -> {
            System.out.println("接收消息失败" );
        });
    }
​
}
java 复制代码
package com.my.rabbitmq.six;
​
import com.my.utils.RabbitMQUtils;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
​
/**
 * @author zhupanlin
 * @version 1.0
 * @description: TODO
 * @date 2023/11/30 12:24
 */
public class ReceiveLogsTopic02 {
​
    // 交换机名称
    public static final String EXCHANGE_NAME = "topic_logs";
​
    public static void main(String[] args) throws Exception{
​
        Channel channel = RabbitMQUtils.getChannel();
        // 声明交换机
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
        // 声明队列
        String queueName = "Q2";
        channel.queueDeclare(queueName, false, false,false, null);
        channel.queueBind(queueName, EXCHANGE_NAME, "lazy.#");
​
        System.out.println("等待接收消息");
​
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            System.out.println("队列" + queueName + "的routingKey:" + message.getEnvelope().getRoutingKey());
            System.out.println("接收到消息:" + new String(message.getBody()));
        };
        
        // 接收消息
        channel.basicConsume(queueName, true, deliverCallback, (consumerTag) -> {
            System.out.println(consumerTag + "接收消息失败");
        });
​
    }
​
​
}
相关推荐
计算机毕设指导67 分钟前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
Gu Gu Study8 分钟前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
Chris _data11 分钟前
二叉树oj题解析
java·数据结构
牙牙70516 分钟前
Centos7安装Jenkins脚本一键部署
java·servlet·jenkins
paopaokaka_luck24 分钟前
[371]基于springboot的高校实习管理系统
java·spring boot·后端
以后不吃煲仔饭37 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师37 分钟前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
The_Ticker43 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
大数据编程之光1 小时前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
爪哇学长1 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法