6.rabbitmq中exchange的几种形式

本文详细介绍了RabbitMQ中exchange的三种主要类型:fanout、direct和topic。fanout类型将消息广播到所有队列,适合日志系统;direct类型基于routingKey将消息定向到特定队列,提供了一定的灵活性;topic类型则允许使用通配符路由,更适用于复杂的消息过滤场景。此外,还展示了如何通过binding设置这些交换机与队列的关系,并提供了生产者和消费者代码示例。
摘要由CSDN通过智能技术生成

rabbitmq中exchange的几种形式

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

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

交换机一共有以下几种类型

  • direct:直接
  • topic:主题
  • headers:标题
  • fanout:扇出

什么是 bingding 呢,binding 其实是 exchange 和 queue 之间的桥梁,它告诉我们 exchange 和那个队 列进行了绑定关系。

临时队列

通过使用以下方式来创建一个临时队列,命名随机,一旦我们断开了消费者的连接,队列将被自动删除。

String queue = channel.queueDeclare().getQueue();

在这里插入图片描述

Fanout类型

Fanout 这种类型非常简单。正如从名称中猜到的那样,它是将接收到的所有消息广播到它知道的所有队列中。

案例:构建一个简单的日志系统,生产者将发出日志消息,我们启动两个消费者,第一个消费者将日志持久化到磁盘中,第二个消费者会在控制台打印在屏幕上。即生产者将消息广播给所有消费者

在这里插入图片描述

生产者演示
/**
 *  fanout 类型 生产者
 */
public class FanoutProducer {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        /**
         * 声明一个exchange
         *      String exchange:exchange的名称
         *      String type:exchange的类型
         */
        channel.exchangeDeclare(ExchangeNames.LOGS,"fanout");
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()){
            String message = scanner.nextLine();
						channel.basicPublish(ExchangeNames.LOGS,"",null,message.getBytes(StandardCharsets.UTF_8));
            System.out.println("生产者发出消息"+ message);
        }
    }
}
消费者1(写入磁盘)
/**
 * fanout 类型 消费者1
 */
public class FanoutCustomer1 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.LOGS,"fanout");
        String queue = channel.queueDeclare().getQueue();
        channel.queueBind(queue,ExchangeNames.LOGS,"");
        System.out.println("fanoutCustomer1 等待接收消息,把消息写到磁盘中");
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收到数据成功:"+receive+",写入磁盘中");
        };
        channel.basicConsume(queue,true,deliverCallback,consumerTag -> {});
    }
}
消费者2(输出在控制台)
/**
 * fanout 类型消费者2
 */
public class FanoutCustomer2 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.LOGS,"fanout");
        String queue = channel.queueDeclare().getQueue();
        channel.queueBind(queue,ExchangeNames.LOGS,"");
        System.out.println("fanoutCustomer2 等待接收消息,把消息打印在控制台");
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收到数据成功:"+receive+",打印到控制台。。。");
        };
        channel.basicConsume(queue,true,deliverCallback,consumerTag -> {});
    }
}

Exchange和queue的绑定关系如下图所示

在这里插入图片描述

Direct类型

fanout类型的并不能给我们带来很大的灵活性,它只能进行无意义的广播,而direct类型可以在队列和exchange的bingding中指定一个routingKey,消息只去到它绑定的routingKey中去。

在这里插入图片描述

  • 如图所示,exchange绑定了两个队列,绑定类型事direct,队列console的绑定键为warninginfo,而disk的绑定键为error
  • 在这种情况下,生产者发布消息到exchange上,绑定为warninginfo的会发布到队列console上,绑定为error的会发布到队列disk上,其他消息会被丢弃。

在这里插入图片描述

  • 如果exchange的绑定类型是direct,但是它绑定的多个队列的key都相同,在这种情况下虽然绑定类型事direct,但是它表现的就和fanout有点类似了,就跟广播差不多。
生产者
/**
 * direct 类型 生产者
 */
public class DirectProducer {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        //声明exchange类型
        channel.exchangeDeclare(ExchangeNames.DIRECT_LOG,"direct");
        //声明binding关系
        Map<String,String> bindingKeys = new HashMap<>();
        bindingKeys.put("info","普通info信息");
        bindingKeys.put("error","错误error信息");
        bindingKeys.put("warning","警告warning信息");
        bindingKeys.put("debug","调试debug信息");
        //发送消息
        for (Map.Entry<String, String> entry : bindingKeys.entrySet()) {
            String key = entry.getKey();
            String message = entry.getValue();    						   		  channel.basicPublish(ExchangeNames.DIRECT_LOG,key,null,message.getBytes(StandardCharsets.UTF_8));
            System.out.println("生产者发出消息:消息类型为--"+key+",内容为:"+message);
        }
    }
}
消费者1
/**
 * direct 类型 消费者1
 */
public class DirectCustomer1 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.DIRECT_LOG, BuiltinExchangeType.DIRECT);

        String queueName = "console";
        channel.queueDeclare(queueName,false,false,false,null);
        channel.queueBind(queueName,ExchangeNames.DIRECT_LOG,"info");
        channel.queueBind(queueName,ExchangeNames.DIRECT_LOG,"warning");
        System.out.println("DirectCustomer1 等待接收消息,接收info和warning 的消息类型");

        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收绑定键:"+message.getEnvelope().getRoutingKey()+",消息 :"+receive);
        };
        channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {});
    }
}
消费者2
/**
 * direct 类型 消费者2
 */
public class DirectCustomer2 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.DIRECT_LOG, BuiltinExchangeType.DIRECT);

        String queueName = "disk";
        channel.queueDeclare(queueName,false,false,false,null);
        channel.queueBind(queueName,ExchangeNames.DIRECT_LOG,"error");
        System.out.println("DirectCustomer2 等待接收消息,接收error 的消息类型");

        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收绑定键:"+message.getEnvelope().getRoutingKey()+",消息 :"+receive+",保存到磁盘");
        };
        channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {});
    }
}

direct类型的binging关系

在这里插入图片描述

topic类型

尽管使用 direct 交换机改进了我们的系统,但是它仍然存在局限性-比方说我们想接收的日志类型有 info.baseinfo.advantage,某个队列只想 info.base 的消息,那这个时候 direct 就办不到了。这个时候就只能使用 topic 类型。

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

在这些规则列表中

  • *可以代替一个单词
  • #可以代替零个或多个单词
  • 当一个队列绑定键是#,那么这个队列将接收所有数据,就有点像fanout
  • 如果队列绑定键中没有#*出现,那么该队列绑定类型就是direct

在这里插入图片描述

生产者
/**
 * topic 类型 生产者
 */
public class TopicProducer {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        //声明exchange类型
        channel.exchangeDeclare(ExchangeNames.TOPIC_LOG, BuiltinExchangeType.TOPIC);
        //声明binding关系
        Map<String,String> bindingKeys = new HashMap<>();
        bindingKeys.put("error.bus.core","被Q1和Q2收到");
        bindingKeys.put("error.common.print","被Q1和Q2收到");
        bindingKeys.put("common.base.core","被Q1收到");
        bindingKeys.put("error.bus","被Q2收到");
        bindingKeys.put("file.common.upload","被Q1收到");
        //发送消息
        for (Map.Entry<String, String> entry : bindingKeys.entrySet()) {
            String key = entry.getKey();
            String message = entry.getValue();
            channel.basicPublish(ExchangeNames.TOPIC_LOG,key,null,message.getBytes(StandardCharsets.UTF_8));
            System.out.println("生产者发出消息:消息类型为--"+key+",内容为:"+message);
        }
    }
}
消费者1
/**
 * topic 类型 消费者1
 */
public class TopicCustomer1 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.TOPIC_LOG, BuiltinExchangeType.TOPIC);

        String queueName = "Q1";
        channel.queueDeclare(queueName,false,false,false,null);
        channel.queueBind(queueName,ExchangeNames.TOPIC_LOG,"*.*.core");
        channel.queueBind(queueName,ExchangeNames.TOPIC_LOG,"*.common.*");
        System.out.println("TopicCustomer1 等待接收消息,接收*.*.core和*.common.* 的消息类型");

        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收绑定键:"+message.getEnvelope().getRoutingKey()+",消息 :"+receive);
        };
        channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {});
    }
}

消费者2
/**
 * topic 类型 消费者2
 */
public class TopicCustomer2 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.TOPIC_LOG, BuiltinExchangeType.TOPIC);

        String queueName = "Q2";
        channel.queueDeclare(queueName,false,false,false,null);
        channel.queueBind(queueName,ExchangeNames.TOPIC_LOG,"error.#");
        System.out.println("TopicCustomer1 等待接收消息,接收error.#的消息类型");

        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收绑定键:"+message.getEnvelope().getRoutingKey()+",消息 :"+receive);
        };
        channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {});
    }
}

topic中的binding关系

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RabbitMQ 发消息有以下几种方式: 1. 简单模式(Simple Mode):在简单模式下,生产者直接将消息发送到队列,消费者从队列接收消息。这种方式是最简单的方式,适用于简单的场景。 2. 工作队列模式(Work Queue Mode):在工作队列模式下,生产者将消息发送到一个队列,多个消费者同时监听这个队列,每个消息只能被一个消费者接收。这种方式可以实现任务的并发处理。 3. 发布/订阅模式(Publish/Subscribe Mode):在发布/订阅模式下,生产者将消息发送到一个交换机(Exchange,交换机将消息广播给所有绑定到它的队列。每个消费者都会接收到交换机发送的消息。这种方式适用于需要将消息广播给多个消费者的场景。 4. 路由模式(Routing Mode):在路由模式下,生产者将消息发送到一个交换机,并指定一个路由键(Routing Key),消费者根据路由键来选择接收哪些消息。这种方式可以实现消息的有选择性地发送给特定的消费者。 5. 主题模式(Topic Mode):在主题模式下,生产者将消息发送到一个交换机,并指定一个主题(Topic),消费者可以使用通配符来匹配主题,选择接收哪些消息。这种方式可以实现更灵活的消息过滤和选择。 6. 高级模式(Advanced Mode):除了以上几种常见的方式,RabbitMQ 还提供了一些高级的消息发送方式,如消息持久化、消息优先级、消息过期等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值