前言
本文主要介绍RabbitMQ的三种Exchange模式,分别为Direct ,Topic ,Fanout 。
一、Direct
发送到该Exchange上的消息,会按照routing key路由到指定的Queue。该routing key必须和binding key完全匹配。
示例
可以看到,direct exchange X绑定了两个Queue,其中,Q1由binding key ‘orange’绑定,Q2有两个binding key,分别为‘black’和‘green’。
在这样的设置中,将使用routing key ‘orange’将要发布到交换机的消息 路由到队列Q1。routing key 为‘black’或‘green’的消息将转到Q2。所有其他消息将被丢弃。
示例代码
先引入jar包
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>3.6.5</version>
</dependency>
消费端
// 通过ConnectionFactory 创建一个Connection
ConnectionFactory connectionFactory = new ConnectionFactory() ;
// 配置连接的host
connectionFactory.setHost("127.0.0.1");
// 配置连接的端口
connectionFactory.setPort(5672);
// 配置连接的virtualhost
connectionFactory.setVirtualHost("/");
connectionFactory.setAutomaticRecoveryEnabled(true);
connectionFactory.setNetworkRecoveryInterval(3000);
// 创建Connection
Connection connection = connectionFactory.newConnection();
// 创建Channel
Channel channel = connection.createChannel();
// 声明
String exchangeName = "exchange";
String exchangeType = "direct";
String queueName = "queue";
String routingKey = "routingKey";
// 声明Exchange
channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
// 声明队列
channel.queueDeclare(queueName, false, false, false, null);
// 绑定Exchange和队列
channel.queueBind(queueName, exchangeName, routingKey);
// 声明消费者
QueueingConsumer consumer = new QueueingConsumer(channel);
// 参数:队列名称、是否自动ACK、Consumer
channel.basicConsume(queueName, true, consumer);
// 循环获取消息
while(true){
//获取消息,如果没有消息,这一步将会一直阻塞
Delivery delivery = consumer.nextDelivery();
String msg = new String(delivery.getBody());
System.out.println("收到消息:" + msg);
}
生产端
//1 创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
//2 创建Connection
Connection connection = connectionFactory.newConnection();
//3 创建Channel
Channel channel = connection.createChannel();
//4 声明
String exchangeName = "exchange";
String routingKey = "routingKey";
//5 发送
String msg = "RabbitMQ Direct Exchange Message ... ";
channel.basicPublish(exchangeName, routingKey , null , msg.getBytes());
channel.close();
connection.close();
注意:Direct模式可以使用RabbitMQ自带的Exchange:defaut exchange,可以不将Exchang进行任何的绑定(binding),消息传递时,routing key必须和Queue名称完全匹配, 消息才会被路由,反之消息将被丢弃
二、Topic
发送到topic exchange的消息的 routing key,必须是以点分隔的单词列表。示例:
“ stock.usd.nyse ”,“ nyse.vmw ”,“quick.orange.rabbit ”。
routing key中可以包含任意多个单词,最多255个字节。
binding key也必须采用相同的形式。topic exchange背后的逻辑 类似于direct exchange-用特定routing key发送的消息将传递到所有匹配binding key绑定的队列。但是,binding key有两个重要的特殊情况:
● *(星号)可以代替一个单词。
● #(哈希)可以替代零个或多个单词。
示例
在此示例中,我们创建了三个绑定:Q1与绑定键“ * .orange.* ”绑定,Q2与“ *.*.rabbit ”和“ lazy.# ”绑定。
其中:
routing key设置为“ quick.orange.rabbit ”的消息将传递到两个队列。消息“ lazy.orange.elephant ”也将发送给他们两个。
而“ quick.orange.fox ”只会进入第一个队列,
“ lazy.brown.fox ”只会进入第二个队列。
“ lazy.pink.rabbit ”将被传递到第二队列一次,即使有两个绑定匹配。
“ quick.brown.fox ”与任何绑定都不匹配,因此将被丢弃。
如果我们违约并发送一个或四个单词的消息,例如“orange”或“ quick.orange.male.rabbit ”,会发生什么?好吧,这些消息将不匹配任何绑定,并且将会丢失。
另一方面,“ lazy.orange.male.rabbit ”即使有四个单词,也将匹配最后一个绑定,并将其传送到第二个队列。
代码示例
消费端
ConnectionFactory connectionFactory = new ConnectionFactory() ;
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setAutomaticRecoveryEnabled(true);
connectionFactory.setNetworkRecoveryInterval(3000);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
//4 声明
String exchangeName = "exchange";
String exchangeType = "topic";
String queueName = "queue";
//String routingKey = "user.*";
String routingKey = "user.#";
channel.exchangeDeclare(exchangeName, exchangeType, true, false, false, null);
channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName, exchangeName, routingKey);
QueueingConsumer consumer = new QueueingConsumer(channel);
// 参数:队列名称、是否自动ACK、Consumer
channel.basicConsume(queueName, true, consumer);
// 循环获取消息
while(true){
// 获取消息,如果没有消息,这一步将会一直阻塞
Delivery delivery = consumer.nextDelivery();
String msg = new String(delivery.getBody());
System.out.println("收到消息:" + msg + ", RoutingKey: " + delivery.getEnvelope().getRoutingKey());
}
生产端
//1 创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
//2 创建Connection
Connection connection = connectionFactory.newConnection();
//3 创建Channel
Channel channel = connection.createChannel();
//4 声明
String exchangeName = "exchange";
String routingKey1 = "user.save";
String routingKey2 = "user.update";
String routingKey3 = "user.delete.abc";
//5 发送
String msg = "RabbitMQ Topic Exchange Message ...";
channel.basicPublish(exchangeName, routingKey1 , null , msg.getBytes());
//channel.basicPublish(exchangeName, routingKey2 , null , msg.getBytes());
//channel.basicPublish(exchangeName, routingKey3 , null , msg.getBytes());
channel.close();
connection.close();
三、Fanout
发送到fanout exchange的所有消息都将广播到它所绑定的(binding)所有队列中,因此routing key在此将不起作用。
示例
所有发送到exchange X的消息都会广播到与其绑定的两个队列中,且routing key在此将被忽略。
总结
以上三种模式就是最常使用的三种Exchange 模式。