RabbitMQ 04 订阅模式/路由模式

rabbitmq六种工作模式

3.发布订阅模式

即向多个消费者传递同一条信息
image

1).Exchanges 交换机

RabbitMQ消息传递模型的核心思想是,生产者永远不会将任何消息直接发送到队列。

相反,生产者只能向交换机(Exchange)发送消息。交换机是一个非常简单的东西。一边接收来自生产者的消息,另一边将消息推送到队列。交换器必须确切地知道如何处理它接收到的消息。它应该被添加到一个特定的队列中吗?它应该添加到多个队列中吗?或者它应该被丢弃。这些规则由exchange的类型定义。

有几种可用的交换类型:direct、topic、header和fanout
创建fanout交换机logs: c.exchangeDeclare("logs", "fanout");
c.exchangeDeclare("logs", BuiltinExchangeType.FANOUT);

fanout交换机非常简单。它只是将接收到的所有消息广播给它所知道的所有队列。

2).绑定 Bindings

image

创建了一个fanout交换机和一个队列。现在我们需要告诉exchange向指定队列发送消息。exchange和队列之间的关系称为绑定。

//指定的队列,与指定的交换机关联起来
//称为绑定 -- binding
//第三个参数时 routingKey, 由于是fanout交换机, 这里忽略 routingKey
ch.queueBind(queueName, "logs", "");
3).整体代码

1.生产者
最重要的更改是,我们现在希望将消息发布到logs交换机,而不是无名的日志交换机。我们需要在发送时提供一个routingKey,但是对于fanout交换机类型,该值会被忽略。

public class Producer {
    public static void main(String[] args) throws Exception {
        //建立连接
 ConnectionFactory f = new ConnectionFactory();
 f.setHost("192.168.64.140");
 f.setPort(5672);
 f.setUsername("admin");
 f.setPassword("admin");
 Connection con = f.newConnection();
 Channel c = con.createChannel();
 //定义fanout类型交换机:logs
 //c.exchangeDeclare("logs", "fanout"); c.exchangeDeclare("logs", BuiltinExchangeType.FANOUT);
 //向交换机发送信息
 while (true){
            System.out.println("输入消息:");
 String msg = new Scanner(System.in).nextLine();
 c.basicPublish("logs",
 "",
 null, msg.getBytes());
 }
    }
}

2.消费者
如果还没有队列绑定到交换器,消息就会丢失,但这对我们来说没有问题;如果还没有消费者在听,我们可以安全地丢弃这些信息。

public class Consumer {
    public static void main(String[] args) throws Exception {
        //建立连接
 ConnectionFactory f = new ConnectionFactory();
 f.setHost("192.168.64.140");
 f.setPort(5672);
 f.setUsername("admin");
 f.setPassword("admin");
 Connection con = f.newConnection();
 Channel c = con.createChannel();
 //1.定义随机队列 2.定义交换机 3.绑定
 //随机命名,非持久,独占,自动删除
 String queue = UUID.randomUUID().toString();
 c.queueDeclare(queue,
 false, true, true, null);
 c.exchangeDeclare("logs", BuiltinExchangeType.FANOUT);
 //第三个参数对发布订阅模式fanout交换机无效
 c.queueBind(queue, "logs", "");
 DeliverCallback deliverCallback = new DeliverCallback() {
            @Override
 public void handle(String consumerTag, Delivery message) throws IOException {
                String msg = new String(message.getBody());
 System.out.println("收到:"+msg);
 }
        };
 CancelCallback cancelCallback = new CancelCallback() {
            @Override
 public void handle(String consumerTag) throws IOException {
            }
        };
 //正常的消费数据
 c.basicConsume(queue,
 true, deliverCallback,
 cancelCallback);
 }
}

4.路由模式

路由模式与订阅模式不同之处在于,我们将向其添加一个特性—我们将只订阅所有消息中的一部分.本文中已添加err/info/warning等报错提示来示范.
image

1).绑定 Bindings

绑定是交换机和队列之间的关系。这可以简单地理解为:队列对来自此交换的消息感兴趣。

绑定可以使用额外的routingKey参数。为了避免与basic_publish参数混淆,我们将其称为bindingKey。这是我们如何创建一个键绑定:

ch.queueBind(queueName, EXCHANGE_NAME, "black");

bindingKey的含义取决于交换机类型。我们前面使用的fanout交换机完全忽略它。

2).直连交换机 Direct exchange

上一节中的日志系统向所有消费者广播所有消息。我们希望扩展它,允许根据消息的严重性过滤消息。

前面我们使用的是fanout交换机,这并没有给我们太多的灵活性——它只能进行简单的广播。

我们将用直连交换机(Direct exchange)代替。它背后的路由算法很简单——消息传递到bindingKey与routingKey完全匹配的队列。

3).多重绑定 Multiple bindings

使用相同的bindingKey绑定多个队列是完全允许的。可以使用binding key "black"将X与Q1和Q2绑定。在这种情况下,直连交换机的行为类似于fanout,并将消息广播给所有匹配的队列。一条路由键为black的消息将同时发送到Q1和Q2。

4).更改

1.发送消息
我们将提供日志级别作为routingKey,这样,接收程序将能够选择它希望接收的级别

//参数1: 交换机名
//参数2: routingKey, 路由键,这里我们用日志级别,如"error","info","warning"
//参数3: 其他配置属性
//参数4: 发布的消息数据 
ch.basicPublish("direct_logs", "error", null, message.getBytes());

2.接收消息
我们将为感兴趣的每个日志级别创建一个新的绑定

ch.queueBind(queueName, "logs", "info");
ch.queueBind(queueName, "logs", "warning");
5).完整代码

1.生产者

public class Producer {
    public static void main(String[] args) throws Exception {
        //建立连接
 ConnectionFactory f = new ConnectionFactory();
 f.setHost("192.168.64.140");
 f.setPort(5672);
 f.setUsername("admin");
 f.setPassword("admin");
 Connection con = f.newConnection();
 Channel c = con.createChannel();
 //定义fanout类型交换机:logs
 //c.exchangeDeclare("logs", "fanout"); c.exchangeDeclare("direct_logs", BuiltinExchangeType.DIRECT);
 //向交换机发送信息
 while (true){
            System.out.println("输入消息:");
 String msg = new Scanner(System.in).nextLine();
 System.out.println("输入路由键:");
 String key = new Scanner(System.in).nextLine();
 c.basicPublish("direct_logs",
 key, //路由键关键词
 null,
 msg.getBytes());
 }
    }
}

2.消费者

public class Consumer {
    public static void main(String[] args) throws Exception {
        //建立连接
 ConnectionFactory f = new ConnectionFactory();
 f.setHost("192.168.64.140");
 f.setPort(5672);
 f.setUsername("admin");
 f.setPassword("admin");
 Connection con = f.newConnection();
 Channel c = con.createChannel();
 //1.定义随机队列 2.定义交换机 3.绑定
 //随机命名,非持久,独占,自动删除
 String queue = UUID.randomUUID().toString();
 c.queueDeclare(queue,
 false, true, true, null);
 c.exchangeDeclare("direct_logs", BuiltinExchangeType.DIRECT);
 //用输入绑定键进行绑定
 System.out.println("输入绑定键,用空格隔开:");
 String s = new Scanner(System.in).nextLine();
 String[] a = s.split(" "); //["aaa","bbb","ccc"]
 for (String key:a){
            c.queueBind(queue, "direct_logs", key);
 }
        DeliverCallback deliverCallback = new DeliverCallback() {
            @Override
 public void handle(String consumerTag, Delivery message) throws IOException {
                String msg = new String(message.getBody());
 String key = message.getEnvelope().getRoutingKey();
 System.out.println("收到:"+msg+" - "+key);
 }
        };
 CancelCallback cancelCallback = new CancelCallback() {
            @Override
 public void handle(String consumerTag) throws IOException {
            }
        };
 //正常的消费数据
 c.basicConsume(queue,
 true, deliverCallback,
 cancelCallback);
 }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RabbitMQ发布订阅模式是一种基于交换机(exchange)和队列(queue)的消息传递方式,它可以将消息广播给所有订阅了相关队列的消费者。下面是使用RabbitMQ实现发布订阅模式的基本步骤: 1. 创建一个连接和通道(channel)对象: ``` ConnectionFactory factory = new ConnectionFactory(); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); ``` 2. 声明一个交换机: ``` String exchangeName = "logs"; channel.exchangeDeclare(exchangeName, "fanout"); ``` 在声明交换机时,需要指定交换机的名称和类型。这里使用的是fanout类型,它会将所有消息广播给所有绑定到该交换机队列。 3. 声明一个队列: ``` String queueName = channel.queueDeclare().getQueue(); ``` 在声明队列时,如果不指定队列名称,则RabbitMQ会自动生成一个队列名称,并返回给客户端。 4. 将队列绑定到交换机上: ``` channel.queueBind(queueName, exchangeName, ""); ``` 5. 发布消息到交换机上: ``` String message = "Hello World!"; channel.basicPublish(exchangeName, "", null, message.getBytes("UTF-8")); ``` 在发布消息时,需要指定交换机的名称和消息内容。由于是发布订阅模式,所以这里的路由键设置为"",表示消息将被发送到所有绑定到该交换机上的队列中。 6. 接收消息: ``` Consumer consumer = new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String message = new String(body, "UTF-8"); System.out.println("Received message: " + message); } }; channel.basicConsume(queueName, true, consumer); ``` 在接收消息时,需要创建一个消费者对象,并将其注册到队列中。在这里,我们使用了一个DefaultConsumer类的子类来实现消费者对象,它会将收到的消息输出到控制台上。注意,在消费完消息后需要向RabbitMQ服务器发送确认消息,以便告诉服务器这条消息已经被处理完毕。 以上就是使用RabbitMQ实现发布订阅模式的基本步骤。在实际开发中,我们可以根据具体的需求来调整这些步骤的顺序和参数设置,以实现不同的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值