RabbitMQ学习笔记[5]-RabbitMQ消息模型-Fanout广播模型

本文介绍RabbitMQ消息模型中的Fanout交换机原理及应用,演示了如何通过Fanout交换机实现消息广播,并详细展示了生产者与消费者的开发实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The core idea in the messaging model in RabbitMQ is that the producer never sends any messages directly to a queue. Actually, quite often the producer doesn't even know if a message will be delivered to any queue at all.

Instead, the producer can only send messages to an exchange. An exchange is a very simple thing. On one side it receives messages from producers and the other side it pushes them to queues. The exchange must know exactly what to do with a

message it

receives. Should it be appended to a particular queue? Should it be appended to many queues? Or should it get discarded. The rules for that are defined by the exchange type.

译:

RabbitMQ消息传递模型的核心思想是生产者从不将任何消息直接发送到队列。实际上,生产者通常甚至根本不知道是否将消息传递到任何队列。

相反,生产者只能将消息发送到交换机。交流是一件非常简单的事情。一方面,它接收来自生产者的消息,另一方面,将它们推入队列。交易所必须确切知道如何处理收到的消息。是否应将其附加到特定队列?是否应该将其附加到许多队列中?还是应该将其丢

弃。规则由交换类型定义 。

1. Fanout

Fanout,也称为广播。

在广播模式下,消息发送流程:

  1.  可以有多个消费者
  2. 每个消费者有自己的queue
  3. 每个队列都要绑定到exchange
  4. 生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个queue,生产者无法确定
  5. 交换机把消息发送给绑定过的队列
  6. 队列的消费者都能拿到消息。实现一条消息被多个消费者消费 

2. 开发生产者

package fanout;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import utils.RabbitMQUtil;

import java.io.IOException;

public class Provider {

    public static void main(String[] args) throws IOException {
        // 获取连接对象
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = RabbitMQUtil.getChannel(connection);
        if (null == channel) return;

        // 声明fanout交换机
        // 参数1 exchange:交换机名称
        // 参数2 type:交换机类型 fanout广播类型
        channel.exchangeDeclare("my_exchange", "fanout");

        // 发送消息
        // 参数1 exchange:交换机名称
        // 参数2 routingKey:路由,如果存在消息将以指定的名称路由到队列
        // 参数3 props:消息额外参数
        // 参数4 消息内容
        channel.basicPublish("my_exchange", "", null, "hello rabbitmq fanout !!!".getBytes());

        // 关闭连接释放资源
        RabbitMQUtil.close(channel, connection);
    }

}

As you may remember previously we were using queues that had specific names (remember hello and task_queue?). Being able to name a queue was crucial for us -- we needed to point the workers to the same queue. Giving a queue a name is important

when you want to share the queue between producers and consumers.

But that's not the case for our logger. We want to hear about all log messages, not just a subset of them. We're also interested only in currently flowing messages not in the old ones. To solve that we need two things.

Firstly, whenever we connect to Rabbit we need a fresh, empty queue. To do this we could create a queue with a random name, or, even better - let the server choose a random queue name for us.

Secondly, once we disconnect the consumer the queue should be automatically deleted.

您可能还记得,我们使用的是具有特定名称的队列(还记得hellowordtask_queue吗?)。能够命名队列对我们来说至关重要-我们需要将工人指向同一队列。当您想在生产者和消费者之间共享队列时,给队列命名很重要。

但这不是我们的记录器的情况。我们希望听到所有日志消息,而不仅仅是它们的一部分。我们也只对当前正在发送的消息感兴趣,而对旧消息不感兴趣。

为了解决这个问题,我们需要两件事。

首先,无论何时我们连接到Rabbit,我们都需要一个全新的空队列。为此,我们可以创建一个具有随机名称的队列,或者甚至更好-让服务器为我们选择一个随机队列名称。

其次,一旦我们断开了使用者的连接,队列将被自动删除。

3. 开发消费者

消费者-one

        // 获取连接
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = RabbitMQUtil.getChannel(connection);
        if (null == channel) return;

        // 通道绑定交换机
        channel.exchangeDeclare("my_exchange", "fanout");

        // 创建临时队列
        String queueName = channel.queueDeclare().getQueue();

        // 绑定队列到交换机
        // 参数1 queue:队列名称
        // 参数2 exchange:交换机名称
        // 参数3 routingKey:路由
        channel.queueBind(queueName, "my_exchange", "");

        // 消费消息
        channel.basicConsume(queueName, true, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者--one--" + new String(body));
            }
        });

消费者-two

        // 获取连接
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = RabbitMQUtil.getChannel(connection);
        if (null == channel) return;

        // 通道绑定交换机
        channel.exchangeDeclare("my_exchange", "fanout");

        // 创建临时队列
        String queueName = channel.queueDeclare().getQueue();

        // 绑定队列到交换机
        // 参数1 queue:队列名称
        // 参数2 exchange:交换机名称
        // 参数3 routingKey:路由
        channel.queueBind(queueName, "my_exchange", "");

        // 消费消息
        channel.basicConsume(queueName, true, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者--two--" + new String(body));
            }
        });

消费者-three

        // 获取连接
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = RabbitMQUtil.getChannel(connection);
        if (null == channel) return;

        // 通道绑定交换机
        channel.exchangeDeclare("my_exchange", "fanout");

        // 创建临时队列
        String queueName = channel.queueDeclare().getQueue();

        // 绑定队列到交换机
        // 参数1 queue:队列名称
        // 参数2 exchange:交换机名称
        // 参数3 routingKey:路由
        channel.queueBind(queueName, "my_exchange", "");

        // 消费消息
        channel.basicConsume(queueName, true, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("消费者--three--" + new String(body));
            }
        });

运行,测试结果:

web管理端

当consumer服务停止后,queue会被自动清除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值