RabbitMQ系列(六)RabbitMQ进阶-Queue队列特性 (三) 发布/订阅 模式(2)-扇形交换机

本文主要是介绍RabbitMQ系列(六)RabbitMQ进阶-Queue队列特性 (三) 发布/订阅 模式(2)-扇形交换机,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

RabbitMQ进阶-Queue队列特性 (三) 发布/订阅 模式(2)-扇形交换机

文章目录

    • RabbitMQ进阶-Queue队列特性 (三) 发布/订阅 模式(2)-扇形交换机
        • 1.发布/订阅 模式
        • 2.Direct 直连交换机
        • 3.Fanout 扇形交换机
          • 3.1 代码实战
            • 3.1.1 生产者
            • 3.1.2 消费者1
            • 3.1.3 消费者2
            • 3.1.4 执行结果

1.发布/订阅 模式

本篇文章紧接 发布订阅模式前篇 RabbitMQ系列(五)RabbitMQ进阶-Queue队列特性 (三) 发布/订阅 模式(1)
本片文章接着讲 发布订阅模式的另外几种交换机

2.Direct 直连交换机

在上篇文章中讲过 RabbitMQ系列(五)RabbitMQ进阶-Queue队列特性 (三) 发布/订阅 模式(1)

3.Fanout 扇形交换机

扇型交换机(fanout)很简单,你可能从名字上就能猜测出来,它把消息发送给它所知道的所有队列,常用场景就是日志系统,本条日志要打印到每一个异步系统中,所以每个系统都要写进自己的log。

这次我们采用一个Fanout exchange,然后绑定多个队列,不同的队列还使用不同的RoutingKey,生产者生产消息时候,不设置RoutingKey及设置RoutingKey看一下效果。

3.1 代码实战

先创建包,新建包fanout,包下面新建交换机枚举ExchangeTypeEnum

package fanout;public enum ExchangeTypeEnum {DIRECT("exchange-direct-name", "direct"),FANOUT("exchange-fanout-name", "fanout"),TOPIC("exchange-topic-name", "topic"),HEADER("exchange-header-name", "headers"),UNKNOWN("unknown-exchange-name", "direct");/*** 交换机名字*/private String name;/*** 交换机类型*/private String type;ExchangeTypeEnum(String name, String type) {this.name = name;this.type = type;}public String getName() {return name;}public String getType() {return type;}public static ExchangeTypeEnum getEnum(String type) {ExchangeTypeEnum[] exchangeArrays = ExchangeTypeEnum.values();for (ExchangeTypeEnum exchange : exchangeArrays) {if (exchange.getName().equals(type)) {return exchange;}}return ExchangeTypeEnum.UNKNOWN;}}

创建一个常量类FanoutConst

package fanout;public class FanoutConst {/*** 消息订阅队列 C*/public final static String SUBSCRIBE_QUEUE_NAME_FANOUT_F = "subscribe_queue_fanout_F";/*** 消息订阅队列 D*/public final static String SUBSCRIBE_QUEUE_NAME_FANOUT_G = "subscribe_queue_fanout_G";/*** 路由RoutingKey*/public final static String ROUTINGKEY_F = "rk_subscribe_queue_F";/*** 路由RoutingKey*/public final static String ROUTINGKEY_G = "rk_subscribe_queue_G";}
3.1.1 生产者

队列绑定设置RoutingKey,但是我们的 channel.basicPublish(ExchangeTypeEnum.FANOUT.getName(), “”, null, message.getBytes()); basicPublish生产消息 的RoutingKey是空的,并没有指定 rk

package fanout;import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import conn.MqConnectUtil;
import subscrib3.ExchangeTypeEnum;import java.time.LocalDate;
import java.time.LocalTime;import static fanout.FanoutConst.*;public class FanoutProducer {/*** 生产 Direct直连 交换机的MQ消息*/public static void produceFanoutExchangeMessage(Integer i) throws Exception {// 获取到连接以及mq通道Connection connection = MqConnectUtil.getConnectionDefault();// 从连接中创建通道Channel channel = connection.createChannel();/*声明 直连交换机 交换机 String exchange,* 参数明细* 1、交换机名称* 2、交换机类型,fanout*/channel.exchangeDeclare(ExchangeTypeEnum.FANOUT.getName(), ExchangeTypeEnum.FANOUT.getType());/*声明队列* 参数明细:* 1、队列名称* 2、是否持久化* 3、是否独占此队列* 4、队列不用是否自动删除* 5、参数*/channel.queueDeclare(SUBSCRIBE_QUEUE_NAME_FANOUT_F, true, false, false, null);channel.queueDeclare(SUBSCRIBE_QUEUE_NAME_FANOUT_G, true, false, false, null);/*交换机和队列绑定String queue, String exchange, String routingKey* 参数明细* 1、队列名称* 2、交换机名称* 3、路由key rk.subscribe_queue_direct*/channel.queueBind(SUBSCRIBE_QUEUE_NAME_FANOUT_F, ExchangeTypeEnum.FANOUT.getName(), ROUTINGKEY_F);channel.queueBind(SUBSCRIBE_QUEUE_NAME_FANOUT_G, ExchangeTypeEnum.FANOUT.getName(), ROUTINGKEY_G);//定义消息内容(发布多条消息)String message = "id=" + i + " Hello World! Time:" + LocalDate.now() + " " + LocalTime.now();/* 发送消息 String exchange, String routingKey, BasicProperties props, byte[] body* exchange - 交换机  DirectExchange* queuename - 队列信息* props - 参数信息* message 消息体 byte[]类型*/channel.basicPublish(ExchangeTypeEnum.FANOUT.getName(), "", null, message.getBytes());System.out.println(" ****  Producer  Sent Message: '" + message + "'");//关闭通道和连接channel.close();connection.close();}public static void main(String[] argv) throws Exception {//生产 10条 FanoutExchange 的队列消息for (int i = 0; i < 10; i++) {produceFanoutExchangeMessage(i);}}
}
3.1.2 消费者1

消费者1 消费 F队列

package fanout;import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
import conn.MqConnectUtil;
import subscrib3.ExchangeTypeEnum;import static fanout.FanoutConst.ROUTINGKEY_F;
import static fanout.FanoutConst.SUBSCRIBE_QUEUE_NAME_FANOUT_F;public class FanoutConsumer1 {public static void main(String[] argv) throws Exception {Connection connection = null;Channel channel = null;try {connection = MqConnectUtil.getConnectionDefault();channel = connection.createChannel();/*声明交换机 String exchange* 参数明细* 1、交换机名称* 2、交换机类型,fanout、topic、direct、headers*/channel.exchangeDeclare(ExchangeTypeEnum.FANOUT.getName(), ExchangeTypeEnum.FANOUT.getType());/*声明队列* 参数明细:* 1、队列名称* 2、是否持久化* 3、是否独占此队列* 4、队列不用是否自动删除* 5、参数*/channel.queueDeclare(SUBSCRIBE_QUEUE_NAME_FANOUT_F, true, false, false, null);//交换机和队列绑定String queue, String exchange, String routingKey/*** 参数明细* 1、队列名称* 2、交换机名称* 3、路由key*/channel.queueBind(SUBSCRIBE_QUEUE_NAME_FANOUT_F, ExchangeTypeEnum.FANOUT.getName(), ROUTINGKEY_F);System.out.println(" **** Consumer->1 Waiting for messages. To exit press CTRL+C");QueueingConsumer consumer = new QueueingConsumer(channel);/* 消息确认机制* autoAck true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费* autoAck false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,如果消费者一直没有反馈,那么该消息将一直处于不可用状态*          并且服务器会认为该消费者已经挂掉,不会再给其发送消息,直到该消费者反馈*          !!!!!! 注意这里是 false,手动确认*/channel.basicConsume(SUBSCRIBE_QUEUE_NAME_FANOUT_F, false, consumer);int count = 0;while (count < 10) {QueueingConsumer.Delivery delivery = consumer.nextDelivery();String message = new String(delivery.getBody());System.out.println(" count:" + count + " **** Consumer->1 Received '" + message + "'");doSomeThing(message);//返回确认状态channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);count++;}} catch (Exception e) {e.printStackTrace();} finally {channel.close();connection.close();}}/*** 模拟处理复杂逻辑:休眠100ms** @param message* @throws Exception*/public static void doSomeThing(String message) throws Exception {//遍历Count ,sleep , 接收一条消息后休眠 100 毫秒,模仿复杂逻辑Thread.sleep(100);}
}
3.1.3 消费者2

消费者2 消费 G队列

package fanout;import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
import conn.MqConnectUtil;
import subscrib3.ExchangeTypeEnum;import static fanout.FanoutConst.ROUTINGKEY_F;
import static fanout.FanoutConst.SUBSCRIBE_QUEUE_NAME_FANOUT_G;public class FanoutConsumer2 {public static void main(String[] argv) throws Exception {Connection connection = null;Channel channel = null;try {connection = MqConnectUtil.getConnectionDefault();channel = connection.createChannel();/*声明交换机 String exchange* 参数明细* 1、交换机名称* 2、交换机类型,fanout、topic、direct、headers*/channel.exchangeDeclare(ExchangeTypeEnum.FANOUT.getName(), ExchangeTypeEnum.FANOUT.getType());/*声明队列* 参数明细:* 1、队列名称* 2、是否持久化* 3、是否独占此队列* 4、队列不用是否自动删除* 5、参数*/channel.queueDeclare(SUBSCRIBE_QUEUE_NAME_FANOUT_G, true, false, false, null);//交换机和队列绑定String queue, String exchange, String routingKey/*** 参数明细* 1、队列名称* 2、交换机名称* 3、路由key*/channel.queueBind(SUBSCRIBE_QUEUE_NAME_FANOUT_G, ExchangeTypeEnum.FANOUT.getName(), ROUTINGKEY_F);System.out.println(" **** Consumer->2 Waiting for messages. To exit press CTRL+C");QueueingConsumer consumer = new QueueingConsumer(channel);/* 消息确认机制* autoAck true:表示自动确认,只要消息从队列中获取,无论消费者获取到消息后是否成功消费,都会认为消息已经成功消费* autoAck false:表示手动确认,消费者获取消息后,服务器会将该消息标记为不可用状态,等待消费者的反馈,如果消费者一直没有反馈,那么该消息将一直处于不可用状态*          并且服务器会认为该消费者已经挂掉,不会再给其发送消息,直到该消费者反馈*          !!!!!! 注意这里是 false,手动确认*/channel.basicConsume(SUBSCRIBE_QUEUE_NAME_FANOUT_G, false, consumer);int count = 0;while (count < 10) {QueueingConsumer.Delivery delivery = consumer.nextDelivery();String message = new String(delivery.getBody());System.out.println(" count:" + count + " **** Consumer->2 Received '" + message + "'");doSomeThing(message);//返回确认状态channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);count++;}} catch (Exception e) {e.printStackTrace();} finally {channel.close();connection.close();}}/*** 模拟处理复杂逻辑:休眠100ms** @param message* @throws Exception*/public static void doSomeThing(String message) throws Exception {//遍历Count ,sleep , 接收一条消息后休眠 100 毫秒,模仿复杂逻辑Thread.sleep(100);}
}
3.1.4 执行结果

生产10条消息,消费者1和2全都收到了10条消息
在这里插入图片描述
执行消费者1和消费者2,消息消费完毕,队列清空
在这里插入图片描述

下面我们测试一下,如果我们的生产者,在生产消息的时候随便设置一个RoutingKey,我们到底能不能在队列中找到消息
代码设置 rk为123456

channel.basicPublish(ExchangeTypeEnum.FANOUT.getName(), "123456", null, message.getBytes());

看下队列,依旧是每一个队列中都有10条消息,这说明,FANOUT交换机,生产者设置的RK并不能生效,而是根据绑定的队列来进行所有队列收发消息的
在这里插入图片描述


下篇我们介绍 RabbitMQ系列(七)RabbitMQ进阶-Queue队列特性 (三) 发布/订阅 模式(3)-主题交换机

这篇关于RabbitMQ系列(六)RabbitMQ进阶-Queue队列特性 (三) 发布/订阅 模式(2)-扇形交换机的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/965436

相关文章

Java发送SNMP至交换机获取交换机状态实现方式

《Java发送SNMP至交换机获取交换机状态实现方式》文章介绍使用SNMP4J库(2.7.0)通过RCF1213-MIB协议获取交换机单/多路状态,需开启SNMP支持,重点对比SNMPv1、v2c、v... 目录交换机协议SNMP库获取交换机单路状态获取交换机多路状态总结交换机协议这里使用的交换机协议为常

如何正确识别一台POE交换机的好坏? 选购可靠的POE交换机注意事项

《如何正确识别一台POE交换机的好坏?选购可靠的POE交换机注意事项》POE技术已经历多年发展,广泛应用于安防监控和无线覆盖等领域,需求量大,但质量参差不齐,市场上POE交换机的品牌繁多,如何正确识... 目录生产标识1. 必须包含的信息2. 劣质设备的常见问题供电标准1. 正规的 POE 标准2. 劣质设

Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧

《Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧》本文将通过实际代码示例,深入讲解Python函数的基本用法、返回值特性、全局变量修改以及异常处理技巧,感兴趣的朋友跟随小编一起看看... 目录一、python函数定义与调用1.1 基本函数定义1.2 函数调用二、函数返回值详解2.1 有返

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

修复已被利用的高危漏洞! macOS Sequoia 15.6.1发布

《修复已被利用的高危漏洞!macOSSequoia15.6.1发布》苹果公司于今日发布了macOSSequoia15.6.1更新,这是去年9月推出的macOSSequoia操作... MACOS Sequoia 15.6.1 正式发布!此次更新修复了一个已被黑客利用的严重安全漏洞,并解决了部分中文用户反馈的

RabbitMQ 延时队列插件安装与使用示例详解(基于 Delayed Message Plugin)

《RabbitMQ延时队列插件安装与使用示例详解(基于DelayedMessagePlugin)》本文详解RabbitMQ通过安装rabbitmq_delayed_message_exchan... 目录 一、什么是 RabbitMQ 延时队列? 二、安装前准备✅ RabbitMQ 环境要求 三、安装延时队

从基础到进阶详解Python条件判断的实用指南

《从基础到进阶详解Python条件判断的实用指南》本文将通过15个实战案例,带你大家掌握条件判断的核心技巧,并从基础语法到高级应用一网打尽,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录​引言:条件判断为何如此重要一、基础语法:三行代码构建决策系统二、多条件分支:elif的魔法三、

Python进阶之列表推导式的10个核心技巧

《Python进阶之列表推导式的10个核心技巧》在Python编程中,列表推导式(ListComprehension)是提升代码效率的瑞士军刀,本文将通过真实场景案例,揭示列表推导式的进阶用法,希望对... 目录一、基础语法重构:理解推导式的底层逻辑二、嵌套循环:破解多维数据处理难题三、条件表达式:实现分支

spring AMQP代码生成rabbitmq的exchange and queue教程

《springAMQP代码生成rabbitmq的exchangeandqueue教程》使用SpringAMQP代码直接创建RabbitMQexchange和queue,并确保绑定关系自动成立,简... 目录spring AMQP代码生成rabbitmq的exchange and 编程queue执行结果总结s

C#和Unity中的中介者模式使用方式

《C#和Unity中的中介者模式使用方式》中介者模式通过中介者封装对象交互,降低耦合度,集中控制逻辑,适用于复杂系统组件交互场景,C#中可用事件、委托或MediatR实现,提升可维护性与灵活性... 目录C#中的中介者模式详解一、中介者模式的基本概念1. 定义2. 组成要素3. 模式结构二、中介者模式的特点