前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >AMQP-RabbitMQ/3/发布订阅模式

AMQP-RabbitMQ/3/发布订阅模式

作者头像
喜欢天文的pony站长
发布2020-06-29 12:11:07
6060
发布2020-06-29 12:11:07
举报
文章被收录于专栏:RabbitMQ实战RabbitMQ实战

3. 发布订阅模式 Publish/Subscribe - 全集监听 fanout

一次向多个消费者发送消息

  • 图示

# 个人理解

  • 生产者定义Exchange,同时将Exchange的类型定义为 fanout,并向该Exchange发送消息。
  • 消费者定义队列Queue,并将队列与该交换机进行绑定。之后交换机付负责将消息全量推送给每一个与之绑定的Queue

RabbitMQ中消息传递模型的核心思想是生产者永远不会将任何消息直接发送到队列。实际上,生产者通常甚至不知道消息是否会被传递到任何队列。 相反,生产者只能向Exchange发送消息。Exchange所做的工作非常简单。一方面,它接收来自生产者的消息,另一方面将它们推送到队列。Exchange必须确切知道如何处理它收到的消息。它应该附加到特定队列吗?它应该附加到多个队列吗?或者它应该被丢弃。其规则由交换类型定义 。

有几种交换类型可供选择: direct, topic, headers and fanout

fanout: 将它接收到的消息广播到所有绑定到它的消息队列上。(忽略路由键routingKey)

  • 生产者 - 发布者
代码语言:javascript
复制

package com.futao.springmvcdemo.mq.rabbit.ps;
 


 
import com.futao.springmvcdemo.mq.rabbit.ExchangeTypeEnum;
 
import com.futao.springmvcdemo.mq.rabbit.RabbitMqConnectionTools;
 
import com.rabbitmq.client.BuiltinExchangeType;
 
import com.rabbitmq.client.Channel;
 
import com.rabbitmq.client.Connection;
 
import lombok.Cleanup;
 
import lombok.SneakyThrows;
 
import lombok.extern.slf4j.Slf4j;
 


 
/**
 
 * 发布订阅-发布者
 
 *
 
 * @author futao
 
 * Created on 2019-04-22.
 
 */
 
@Slf4j
 
public class Publisher {
 
 @SneakyThrows
 
 public static void main(String[] args) {
 
 @Cleanup
 
 Connection connection = RabbitMqConnectionTools.getConnection();
 
 @Cleanup
 
 Channel channel = connection.createChannel();
 
 //定义交换器类型
 
        channel.exchangeDeclare(ExchangeTypeEnum.FANOUT.getExchangeName(), BuiltinExchangeType.FANOUT);
 
 String msg = "Hello RabbitMq!";
 
 for (int i = 0; i < 20; i++) {
 
            channel.basicPublish(ExchangeTypeEnum.FANOUT.getExchangeName(), "", null, (msg + i).getBytes());
 
            log.info("Send msg:[{}] success", (msg + i));
 
 }
 
 }
 
}
 
  • 消费者1 - 订阅者1

代码语言:javascript
复制
package com.futao.springmvcdemo.mq.rabbit.ps;
 


 
import com.futao.springmvcdemo.mq.rabbit.ExchangeTypeEnum;
 
import com.futao.springmvcdemo.mq.rabbit.RabbitMqConnectionTools;
 
import com.futao.springmvcdemo.mq.rabbit.RabbitMqQueueEnum;
 
import com.rabbitmq.client.BuiltinExchangeType;
 
import com.rabbitmq.client.Channel;
 
import com.rabbitmq.client.DeliverCallback;
 
import lombok.SneakyThrows;
 
import lombok.extern.slf4j.Slf4j;
 


 
/**
 
 * 发布订阅-订阅者
 
 *
 
 * @author futao
 
 * Created on 2019-04-22.
 
 */
 
@Slf4j
 
public class SubscriberOne {
 
 @SneakyThrows
 
 public static void main(String[] args) {
 
 Channel channel = RabbitMqConnectionTools.getChannel();
 
 //开启持久化队列
 
 boolean durable = true;
 
        channel.queueDeclare(RabbitMqQueueEnum.EXCHANGE_QUEUE_FANOUT_ONE.getQueueName(), durable, false, false, null);
 
 //定义交换器类型
 
        channel.exchangeDeclare(ExchangeTypeEnum.FANOUT.getExchangeName(), BuiltinExchangeType.FANOUT);
 
 //将消息队列与Exchange交换器绑定
 
        channel.queueBind(RabbitMqQueueEnum.EXCHANGE_QUEUE_FANOUT_ONE.getQueueName(), ExchangeTypeEnum.FANOUT.getExchangeName(), "");
 
 //告诉rabbitmq一次只发送一条消息,并且在前一个消息未被处理或者消费之前,不继续发送下一个消息
 
        channel.basicQos(1);
 
        log.info("Waiting for message...");
 
 DeliverCallback deliverCallback = ((consumerTag, message) -> {
 
            log.info("收到消息:[{}],tag:[{}]", new String(message.getBody()), consumerTag);
 
 //acknowledgment应答
 
            channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
 
 try {
 
 Thread.sleep(1000);
 
 } catch (Exception e) {
 


 
 }
 
 });
 
 //关闭自动应答
 
 boolean autoAck = false;
 
        channel.basicConsume(RabbitMqQueueEnum.EXCHANGE_QUEUE_FANOUT_ONE.getQueueName(), autoAck, deliverCallback, consumerTag -> {
 
 });
 
 }
 
}
 
  • 消费者2 - 订阅者2

代码语言:javascript
复制
package com.futao.springmvcdemo.mq.rabbit.ps;
 


 
import com.futao.springmvcdemo.mq.rabbit.ExchangeTypeEnum;
 
import com.futao.springmvcdemo.mq.rabbit.RabbitMqConnectionTools;
 
import com.futao.springmvcdemo.mq.rabbit.RabbitMqQueueEnum;
 
import com.rabbitmq.client.BuiltinExchangeType;
 
import com.rabbitmq.client.Channel;
 
import com.rabbitmq.client.DeliverCallback;
 
import lombok.SneakyThrows;
 
import lombok.extern.slf4j.Slf4j;
 


 
/**
 
 * 发布订阅-订阅者
 
 *
 
 * @author futao
 
 * Created on 2019-04-22.
 
 */
 
@Slf4j
 
public class SubscriberTwo {
 
 @SneakyThrows
 
 public static void main(String[] args) {
 
 Channel channel = RabbitMqConnectionTools.getChannel();
 
 //开启持久化队列
 
 boolean durable = true;
 
        channel.queueDeclare(RabbitMqQueueEnum.EXCHANGE_QUEUE_FANOUT_TWO.getQueueName(), durable, false, false, null);
 
 //定义交换器类型为fanout
 
        channel.exchangeDeclare(ExchangeTypeEnum.FANOUT.getExchangeName(), BuiltinExchangeType.FANOUT);
 
 //将消息队列与Exchange交换器进行绑定
 
        channel.queueBind(RabbitMqQueueEnum.EXCHANGE_QUEUE_FANOUT_TWO.getQueueName(), ExchangeTypeEnum.FANOUT.getExchangeName(), "");
 
 //告诉rabbitmq一次只发送一条消息,并且在前一个消息未被处理或者消费之前,不继续发送下一个消息
 
        channel.basicQos(1);
 
        log.info("Waiting for message...");
 
 DeliverCallback deliverCallback = ((consumerTag, message) -> {
 
            log.info("收到消息:[{}],tag:[{}]", new String(message.getBody()), consumerTag);
 
 //acknowledgment应答
 
            channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
 
 try {
 
 Thread.sleep(2000);
 
 } catch (Exception e) {
 


 
 }
 
 });
 
 //关闭自动应答
 
 boolean autoAck = false;
 
        channel.basicConsume(RabbitMqQueueEnum.EXCHANGE_QUEUE_FANOUT_TWO.getQueueName(), autoAck, deliverCallback, consumerTag -> {
 
 });
 
 }
 
}
 
  • 注意
  • 没有在发布者定义队列,而是定义了交换器Exchange。发布者将消息发送到Exchange,而不是Queue
  • 在订阅者端,每个订阅者定义了自己的消息队列,并且将自己的消息队列与Exchange进行绑定。则在每次发布者向相应的Exchange发送消息的时候,Exchange会将消息发送至订阅了该Exchange的队列。(即:每个订阅者收到的消息都是一样的)
  • 测试结果

代码语言:javascript
复制
>>> 订阅者1
 
[main] INFO mq.rabbit.ps.SubscriberOne - Waiting for message...
 
[pool-1-thread-4] INFO mq.rabbit.ps.SubscriberOne - 收到消息:[Hello RabbitMq!0],tag:[amq.ctag-Fc_B_CoCYUBoBhEcOlC7vw]
 
[pool-1-thread-5] INFO mq.rabbit.ps.SubscriberOne - 收到消息:[Hello RabbitMq!1],tag:[amq.ctag-Fc_B_CoCYUBoBhEcOlC7vw]
 
[pool-1-thread-6] INFO mq.rabbit.ps.SubscriberOne - 收到消息:[Hello RabbitMq!2],tag:[amq.ctag-Fc_B_CoCYUBoBhEcOlC7vw]
 
[pool-1-thread-7] INFO mq.rabbit.ps.SubscriberOne - 收到消息:[Hello RabbitMq!3],tag:[amq.ctag-Fc_B_CoCYUBoBhEcOlC7vw]
 
[pool-1-thread-8] INFO mq.rabbit.ps.SubscriberOne - 收到消息:[Hello RabbitMq!4],tag:[amq.ctag-Fc_B_CoCYUBoBhEcOlC7vw]
 
[pool-1-thread-9] INFO mq.rabbit.ps.SubscriberOne - 收到消息:[Hello RabbitMq!5],tag:[amq.ctag-Fc_B_CoCYUBoBhEcOlC7vw]
 
[pool-1-thread-10] INFO mq.rabbit.ps.SubscriberOne - 收到消息:[Hello RabbitMq!17],tag:[amq.ctag-Fc_B_CoCYUBoBhEcOlC7vw]
 
[pool-1-thread-22] INFO mq.rabbit.ps.SubscriberOne - 收到消息:[Hello RabbitMq!18],tag:[amq.ctag-Fc_B_CoCYUBoBhEcOlC7vw]
 
[pool-1-thread-23] INFO mq.rabbit.ps.SubscriberOne - 收到消息:[Hello RabbitMq!19],tag:[amq.ctag-Fc_B_CoCYUBoBhEcOlC7vw]
 


 


 
>>> 订阅者2
 
[main] INFO mq.rabbit.ps.SubscriberTwo - Waiting for message...
 
[pool-1-thread-4] INFO mq.rabbit.ps.SubscriberTwo - 收到消息:[Hello RabbitMq!0],tag:[amq.ctag-ip59jtcKJBQFC2KU9DperQ]
 
[pool-1-thread-5] INFO mq.rabbit.ps.SubscriberTwo - 收到消息:[Hello RabbitMq!1],tag:[amq.ctag-ip59jtcKJBQFC2KU9DperQ]
 
[pool-1-thread-6] INFO mq.rabbit.ps.SubscriberTwo - 收到消息:[Hello RabbitMq!2],tag:[amq.ctag-ip59jtcKJBQFC2KU9DperQ]
 
[pool-1-thread-7] INFO mq.rabbit.ps.SubscriberTwo - 收到消息:[Hello RabbitMq!3],tag:[amq.ctag-ip59jtcKJBQFC2KU9DperQ]
 
[pool-1-thread-8] INFO mq.rabbit.ps.SubscriberTwo - 收到消息:[Hello RabbitMq!4],tag:[amq.ctag-ip59jtcKJBQFC2KU9DperQ]
 
[pool-1-thread-9] INFO mq.rabbit.ps.SubscriberTwo - 收到消息:[Hello RabbitMq!5],tag:[amq.ctag-ip59jtcKJBQFC2KU9DperQ]
 
[pool-1-thread-10] INFO mq.rabbit.ps.SubscriberTwo - 收到消息:[Hello RabbitMq!17],tag:[amq.ctag-ip59jtcKJBQFC2KU9DperQ]
 
[pool-1-thread-22] INFO mq.rabbit.ps.SubscriberTwo - 收到消息:[Hello RabbitMq!18],tag:[amq.ctag-ip59jtcKJBQFC2KU9DperQ]
 
[pool-1-thread-23] INFO mq.rabbit.ps.SubscriberTwo - 收到消息:[Hello RabbitMq!19],tag:[amq.ctag-ip59jtcKJBQFC2KU9DperQ]
 
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 喜欢天文 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 3. 发布订阅模式 Publish/Subscribe - 全集监听 fanout
  • # 个人理解
相关产品与服务
消息队列 CMQ 版
消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档