上一篇博客中,我们使用了direct类型的交换机,使得消费者有能力进行选择性的消息。但是仍然存在一些局限性:它不能够基于多重条件进行路由选择。 我们可以使用Topic类型的交换机解决这个问题。
Topic类型的Exchange与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key的时候可以使用通配符!这种模型的Routingkey一般都是由一共或多个单词组成,多个单词之间以"."分割,例如:item.insert;
通配符
- #匹配0个或多个词
- *匹配不多不少恰好1个词
比如上图中的 * .orange. * 与Q1队列进行了绑定,* .* . rabbit和lazy.#与Q2队列进行了绑定, 那么生产者发送路由key为user.orange.key会被消费者C1接收到。 发送路由key为user.orange.rabbit的消息,会被消费者C1和消费者C2都接收到。 如果发送lazy或lazy.aa或lazy.aa.aa 都会被消费者C2接收到。
接下来让我们用代码来验证下;
1.定义生产者
public class Provider {
public static void main(String[] args) throws IOException {
//获取连接对象
Connection connection = RabbitMQUtils.getConnection();
//获取通道
Channel channel = connection.createChannel();
//将通道声明指定交换机
//参数1:交换机名称 参数2:交换机的类型 direct 路由类型
//没有交换机会创建一共名为logs的交换机
channel.exchangeDeclare("topics","topic");
//路由Key
String routerKey = "user.orange.key";
//发送消息
channel.basicPublish("topics",routerKey,null,("这是基于topics的 [ "+ routerKey+"]的消息").getBytes());
//关闭连接和通道
RabbitMQUtils.closeChannelAndConnection(channel,connection);
}
}
2.定义消费者1
public class Customer1 {
public static void main(String[] args) throws IOException {
//获取连接对象
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//通道绑定交换机
channel.exchangeDeclare("topics","topic");
//创建一个临时的、唯一的队列
//返回的是 临时队列名
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
//参数1: 队列名称 参数2:交换机名称 参数3:路由名称
channel.queueBind(queueName,"topics","*.orange.*");
//消费消息
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1:"+new String(body));
}
});
}
}
3.定义消费者2
public class Customer2 {
public static void main(String[] args) throws IOException {
//获取连接对象
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//通道绑定交换机
channel.exchangeDeclare("topics","topic");
//创建一个临时的、唯一的队列
//返回的是 临时队列名
String queueName = channel.queueDeclare().getQueue();
//绑定交换机和队列
//参数1: 队列名称 参数2:交换机名称 参数3:路由名称
channel.queueBind(queueName,"topics","*.*.rabbit");
channel.queueBind(queueName,"topics","lazy.#");
//消费消息
channel.basicConsume(queueName,true,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者2:"+new String(body));
}
});
}
}
先运行消费者1和消费者2,在运行生产者。 可以发现只有消费者1接收到了消息
修改生产者的路由Key
String routerKey = "user.orange.rabbit";
再次运行生产者,可以发现消费者1和消费者2都收到了消息
修改生产者路由key
String routerKey = "lazy";
只有消费者2收到了消息。
可以看到,我们通过使用topic类型的交换机,成功实现了多重条件进行路由选择。