总结自:BV15k4y1k7Ep
模式说明
Topic
类型与Direct
相比,都是可以根据Routing key
把消息路由到不同的队列。只不过Topic
类型Exchange
可以让队列在绑定Routing key
的时候使用通配符!
Topic
类型的Routing key
一般都是由一个或多个单词组成,多个单词之间以.
分隔,例如: item.insert
通配符规则:
#
:匹配一个或多个词。
*
:匹配不多不少恰好 1 个词。
举例:
item.#
:能够匹配item.insert.abc
或者item.insert
。
item.*
:只能匹配item.insert
。
图解:
- 红色 Queue:绑定的是
usa.#
,因此凡是以usa.
开头的Routing key
都会被匹配到。 - 黄色 Queue:绑定的是
#.news
,因此凡是以.news
结尾的Routing key
都会被匹配。
代码
1)生产者
使用 Topic 类型的 Exchange,发送消息时用到了item.insert
、item.update
、item.delete
3 种 routing key。。
package com.zhangmingge.rabbitmq.topic;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.zhangmingge.rabbitmq.ConnectionUtil;
/**
* 通配符 Topic 的交换机类型为:topic
*/
public class Producer {
// 交换机名称
static final String TOPIC_EXCHANGE = "topic_exchange";
// 队列名称
static final String TOPIC_QUEUE_1 = "topic_queue_1";
// 队列名称
static final String TOPIC_QUEUE_2 = "topic_queue_2";
public static void main(String[] args) throws Exception {
// 创建连接
Connection connection = ConnectionUtil.getConnection();
// 创建频道
Channel channel = connection.createChannel();
/*
* 声明交换机
* 参数 1:交换机名称
* 参数 2:交换机类型,fanout、topic、topic、headers
*/
channel.exchangeDeclare(TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
// 发送信息
String message = "新增了商品。Topic 模式;routing key 为 item.insert ";
channel.basicPublish(TOPIC_EXCHANGE, "item.insert", null, message.getBytes());
System.out.println("已发送消息:" + message);
// 发送信息
message = "修改了商品。Topic 模式;routing key 为 item.update";
channel.basicPublish(TOPIC_EXCHANGE, "item.update", null, message.getBytes());
System.out.println("已发送消息:" + message);
// 发送信息
message = "删除了商品。Topic 模式;routing key 为 item.delete";
channel.basicPublish(TOPIC_EXCHANGE, "item.delete", null, message.getBytes());
System.out.println("已发送消息:" + message);
// 关闭资源
channel.close();
connection.close();
}
}
注意其中声明交换机为 Topic 类型:
/*
* 声明交换机
* 参数 1:交换机名称
* 参数 2:交换机类型,fanout、topic、topic、headers
*/
channel.exchangeDeclare(TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
并在发送消息时指定了 routing key:
// 发送信息
String message = "新增了商品。Topic 模式;routing key 为 item.insert ";
channel.basicPublish(TOPIC_EXCHANGE, "item.insert", null, message.getBytes());
System.out.println("已发送消息:" + message);
2)消费者 1
消费者 1 接收两种类型的消息:更新商品(item.update
)和删除商品(item.delete
)。
package com.zhangmingge.rabbitmq.topic;
import com.rabbitmq.client.*;
import com.zhangmingge.rabbitmq.ConnectionUtil;
import java.io.IOException;
public class Consumer1 {
public static void main(String[] args) throws Exception {
Connection connection = ConnectionUtil.getConnection();
// 创建频道
Channel channel = connection.createChannel();
// 声明交换机
channel.exchangeDeclare(Producer.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
// 声明(创建)队列
/*
* 参数 1:队列名称
* 参数 2:是否定义持久化队列
* 参数 3:是否独占本次连接
* 参数 4:是否在不使用的时候自动删除队列
* 参数 5:队列其它参数
*/
channel.queueDeclare(Producer.TOPIC_QUEUE_1, true, false, false, null);
// 队列绑定交换机
channel.queueBind(Producer.TOPIC_QUEUE_1, Producer.TOPIC_EXCHANGE, "item.update");
channel.queueBind(Producer.TOPIC_QUEUE_1, Producer.TOPIC_EXCHANGE, "item.delete");
// 创建消费者;并设置消息处理
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
/*
* consumerTag 消息者标签,在 channel.basicConsume 时候可以指定
* envelope 消息包的内容,可从中获取消息 id,消息 routingkey,交换机,消息和重传标志 (收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
// 路由 key
System.out.println("路由 key 为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息 id
System.out.println("消息 id 为:" + envelope.getDeliveryTag());
// 收到的消息
System.out.println("消费者 1-接收到的消息为:" + new String(body, "utf-8"));
}
};
// 监听消息
/*
* 参数 1:队列名称
* 参数 2:是否自动确认,设置为 true 为表示消息接收到自动向 mq 回复接收到了,mq 接收到回复会删除消息,设置为 false 则需要手动确认
* 参数 3:消息接收到后回调
*/
channel.basicConsume(Producer.TOPIC_QUEUE_1, true, consumer);
}
}
注意启动声明交换机为 Topic 类型:
// 声明交换机
channel.exchangeDeclare(Producer.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
并且将队列通过item.update
和item.delete
routing key 与交换机绑定:
// 队列绑定交换机
channel.queueBind(Producer.TOPIC_QUEUE_1, Producer.TOPIC_EXCHANGE, "item.update");
channel.queueBind(Producer.TOPIC_QUEUE_1, Producer.TOPIC_EXCHANGE, "item.delete");
3)消费者 2
消费者 2 接收所有类型的消息:新增商品(item.insert
),更新商品(item.update
)和删除商品(item.delete
)。
package com.zhangmingge.rabbitmq.topic;
import com.rabbitmq.client.*;
import com.zhangmingge.rabbitmq.ConnectionUtil;
import java.io.IOException;
public class Consumer2 {
public static void main(String[] args) throws Exception {
Connection connection = ConnectionUtil.getConnection();
// 创建频道
Channel channel = connection.createChannel();
// 声明交换机
channel.exchangeDeclare(Producer.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
// 声明(创建)队列
/*
* 参数 1:队列名称
* 参数 2:是否定义持久化队列
* 参数 3:是否独占本次连接
* 参数 4:是否在不使用的时候自动删除队列
* 参数 5:队列其它参数
*/
channel.queueDeclare(Producer.TOPIC_QUEUE_2, true, false, false, null);
// 队列绑定交换机
channel.queueBind(Producer.TOPIC_QUEUE_2, Producer.TOPIC_EXCHANGE, "item.*");
// 创建消费者;并设置消息处理
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
/*
* consumerTag 消息者标签,在 channel.basicConsume 时候可以指定
* envelope 消息包的内容,可从中获取消息 id,消息 routingkey,交换机,消息和重传标志 (收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
// 路由 key
System.out.println("路由 key 为:" + envelope.getRoutingKey());
// 交换机
System.out.println("交换机为:" + envelope.getExchange());
// 消息 id
System.out.println("消息 id 为:" + envelope.getDeliveryTag());
// 收到的消息
System.out.println("消费者 2-接收到的消息为:" + new String(body, "utf-8"));
}
};
// 监听消息
/*
* 参数 1:队列名称
* 参数 2:是否自动确认,设置为 true 为表示消息接收到自动向 mq 回复接收到了,mq 接收到回复会删除消息,设置为 false 则需要手动确认
* 参数 3:消息接收到后回调
*/
channel.basicConsume(Producer.TOPIC_QUEUE_2, true, consumer);
}
}
注意其队列绑定交换机时使用了通配符:
// 队列绑定交换机
channel.queueBind(Producer.TOPIC_QUEUE_2, Producer.TOPIC_EXCHANGE, "item.*");
测试
启动所有消费者,然后使用生产者发送消息,在消费者对应的控制台可以查看到生产者发送对应 routing key 对应队列的消息,达到按照需要接收的效果,并且这些 routing key 可以使用通配符。
在执行完测试代码后,其实到 RabbitMQ 的管理后台找到Exchanges
选项卡,点击topic_exchange
的交换机,可以查看到如下的绑定:
小结
Topic 主题模式/通配符模式可以实现发布与订阅模式和路由模式的功能,Topic 在配置 routing key 的时候可以使用通配符,要更加灵活。
标签:TOPIC,Producer,示例,RabbitMQ,Topic,item,交换机,key,channel From: https://www.cnblogs.com/Higurashi-kagome/p/18475737