视频地址
之前我们学习了扇出模式和直接模式,但是他们呢只能完成广播和到指定的某一个routingkey,但是如果我们想要像类似于正则表达式那样完成匹配即可接收就不行了,那么就可以使用主题模式来完成这个需要。
主题模式
- 与扇出和直接模式差不多,只是能够更加精准地匹配地分配到某些指定的队列。
发送到类型是 topic 交换机的消息的 routing_key 不能随意写,必须满足一定的要求,它必须是一个单词列表,以点号分隔开。这些单词可以是任意单词,比如说:“stock.usd.nyse”, “nyse.vmw”, “quick.orange.rabbit”.这种类型的。当然这个单词列表最多不能超过 255 个字节。
在这个规则列表中,有两个替换符是大家需要注意的
*
(星号)可以代替一个单词#
(井号)可以替代零个或多个单词
举例说明:
- quick.orange.rabbit 被队列 Q1Q2 接收到
- lazy.orange.elephant 被队列 Q1Q2 接收到
- quick.orange.fox 被队列 Q1 接收到
- lazy.brown.fox 被队列 Q2 接收到
- lazy.pink.rabbit 虽然满足两个绑定但只被队列 Q2 接收一次
- quick.brown.fox 不匹配任何绑定不会被任何队列接收到会被丢弃
- quick.orange.male.rabbit 是四个单词不匹配任何绑定会被丢弃
- lazy.orange.male.rabbit 是四个单词但匹配 Q2
特殊的:
当一个队列绑定键是#,那么这个队列将接收所有数据,就有点像 fanout 了
如果队列绑定键当中没有#和*出现,那么该队列绑定类型就是 direct 了
实验代码
package com.dongmu.topic;
import com.dongmu.util.RabbitMQUtil;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import java.nio.charset.StandardCharsets;
public class Consumer1 {
private static final String exchange_name = "topic_logs";
public static void main(String[] args) throws Exception {
//获取信道
Channel channel = RabbitMQUtil.getChannel();
//声明交换机
channel.exchangeDeclare(exchange_name, BuiltinExchangeType.TOPIC);
//声明队列
String queueName = "queue1";
channel.queueDeclare(queueName,false,false,false,null);
//将队列和交换机进行绑定
channel.queueBind(queueName,exchange_name,"*.orange.*");
DeliverCallback deliverCallback = (queueTag,message)->{
System.out.println("接收到了消息"+new String(message.getBody(),StandardCharsets.UTF_8));
};
CancelCallback cancelCallback = (mesg)->{
System.out.println("接收消息"+mesg+"失败。");
};
channel.basicConsume(queueName,true,deliverCallback,cancelCallback);
}
}
package com.dongmu.topic;
import com.dongmu.util.RabbitMQUtil;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import java.nio.charset.StandardCharsets;
public class Consumer2 {
private static final String exchange_name = "topic_logs";
public static void main(String[] args) throws Exception {
//获取信道
Channel channel = RabbitMQUtil.getChannel();
//声明交换机
channel.exchangeDeclare(exchange_name, BuiltinExchangeType.TOPIC);
//声明队列
String queueName = "queue2";
channel.queueDeclare(queueName,false,false,false,null);
//将队列和交换机进行绑定
channel.queueBind(queueName,exchange_name,"*.*.rabbit");
channel.queueBind(queueName,exchange_name,"lazy.#");
DeliverCallback deliverCallback = (queueTag,message)->{
System.out.println("接收到了消息"+new String(message.getBody(),StandardCharsets.UTF_8));
};
CancelCallback cancelCallback = (mesg)->{
System.out.println("接收消息"+mesg+"失败。");
};
channel.basicConsume(queueName,true,deliverCallback,cancelCallback);
}
}
package com.dongmu.topic;
import com.dongmu.util.RabbitMQUtil;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import java.util.Scanner;
public class Producer {
private static final String exchange_name = "topic_logs";
public static void main(String[] args) throws Exception {
Channel channel = RabbitMQUtil.getChannel();
channel.exchangeDeclare(exchange_name, BuiltinExchangeType.TOPIC);
String message = "dongmu";
Scanner scanner = new Scanner(System.in);
/*
1:交换机名称
2:路由的routingkey
3:其他的消息参数
4:消息体
*/
while (scanner.hasNext()){
message = scanner.next();
channel.basicPublish(exchange_name,"lazy.orange.elephant",null,message.getBytes());
System.out.println("发送消息"+message+"成功。");
}
}
}
把生产者路由改成lazy.orange.male.rabbit
结果如下
可以发现只有queue2收到了消息。