1.声明
当前的内容用于本人学习和使用Fanout类型的Exchange,主要理解其主要作用
2.Fanout Exchange的官方介绍
-
扇出交换机将消息路由到与其绑定的所有队列,并且路由键将被忽略
。如果将N个队列绑定到扇出交换,则将新消息发布到该交换时,会将消息的副本传递到所有N个队列。扇出交换机非常适合消息的广播路由
。 -
因为扇出交换将消息的副本发送到绑定到它的每个队列,所以它的用例非常相似:
2.1 大型多人在线(MMO)游戏可以将其用于排行榜更新或其他全球性事件
2.2 体育新闻网站可以使用扇出交换以近乎实时的方式向移动客户端分发得分更新
2.3 分布式系统可以广播各种状态和配置更新
2.4 群组聊天可以使用扇出交换在参与者之间分发消息(尽管AMQP没有内置的在线状态概念,因此XMPP可能是更好的选择)
个人理解就是:如果使用交换类型为Fanout类型的Exchange的时候,如果该Exchange中具有多个queue队列,如果向该Fanout类型的Exchange发送消息,那么所有的队列都可以获得该消息的副本,从而实现广播
3.模拟和实现该Fanout广播
1.首先创建Fanout类型的Exchange
当前的Durability使用默认值Durable
2.创建三个队列world1、world2、world3
3.将这三个队列绑定到fanoutTest这个Exchange上面
这里不添加任何Routing Key和Arguments
4.创建三个消费者
public class World1MessageReceiver {
private final static String QUEUE_NAME = "world1";
public static void main(String[] args) throws Exception {
RabbitMqUtils mqUtils = new RabbitMqUtils();
mqUtils.reciver(QUEUE_NAME, true, (consumerTag, delivery) -> {
System.out.println("【world1】==>" + new String(delivery.getBody(), "utf-8"));
});
}
}
public class World2MessageReceiver {
private final static String QUEUE_NAME = "world2";
public static void main(String[] args) throws Exception {
RabbitMqUtils mqUtils = new RabbitMqUtils();
mqUtils.reciver(QUEUE_NAME, true, (consumerTag, delivery) -> {
System.out.println("【world2】==>" + new String(delivery.getBody(), "utf-8"));
});
}
}
public class World3MessageReceiver {
private final static String QUEUE_NAME = "world3";
public static void main(String[] args) throws Exception {
RabbitMqUtils mqUtils = new RabbitMqUtils();
mqUtils.reciver(QUEUE_NAME, true, (consumerTag, delivery) -> {
System.out.println("【world3】==>" + new String(delivery.getBody(), "utf-8"));
});
}
}
5.创建消息生产者
public class WorldMessageSender {
private final static String QUEUE_NAME = "world1";// 这个随便写
@Test
public void testSender() {
RabbitMqUtils mqUtils = new RabbitMqUtils();
for (int i = 0; i < 10; i++) {
mqUtils.send("fanoutTest", QUEUE_NAME, true, ("你好,世界!" + i));
}
}
}
注意这里需要修改原来的RabbitMqUtils中的部分内容
public boolean send(final String exchange, final String queue, final String msg) {
return send(exchange, queue, false, msg);
}
public boolean send(final String exchange, final String queue, boolean durable, final String msg) {
try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {
channel.queueDeclare(queue, durable, false, false, null);
channel.basicPublish(exchange, queue, null, msg.getBytes());
return true;
} catch (IOException | TimeoutException e) {
e.printStackTrace();
return false;
}
}
public void reciver(final String queue, DeliverCallback deliverCallback) throws Exception {
reciver(queue, false, deliverCallback);
}
// 修复问题
public void reciver(final String queue, boolean durable, DeliverCallback deliverCallback) throws Exception {
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(queue, durable, false, false, null);
channel.basicConsume(queue, true, deliverCallback, consumerTag -> {
});
}
让这个接收者和消费者的durable都可以设置为true,如果不设定一致,则存在报错的情况
6.启动三个消费者
7.启动生产者查看情况
发现发送消息到一个队列的时候自动广播到该exchange下的所有的queue中,并且每个消费者都获取了消息
测试成功!
4.总结
1.通过测试发现Fanout类型的Exchange,如果发送消息到其内部的任何一个消息队列,都会自动广播到其他队列中,每个消费者都可以获取数据
2.使用Fanout可以实现广播功能
以上纯属个人见解,如有问题请联系本人!