Topic类型的Exchange与Direct相比,都是可以根据Routing Key把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key的时候使用通配符!
Routingkey 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: item.insert
通配符规则:
#:匹配一个或多个词
*:匹配不多不少恰好1个词
举例:
在这个例子中:
lazy.#:能够匹配lazy.aa.bb或者 lazy.aa
*.orange.*:只能匹配aa.orange.bb
1、声明交换机
/**
* 1、声明交换机
*/
@Test
public void decalreExchange() throws Exception {
String exchange = "hello_topic";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
// 声明exchange,指定类型为topic
channel.exchangeDeclare(exchange, BuiltinExchangeType.TOPIC,true,false,false,new HashMap<>());
}
运行后,可以看到交换机已创建成功
2、声明队列并绑定到交换机
/**
* 2、声明队列并绑定到交换机
*/
@Test
public void decalreQueueAndBind() throws Exception {
String exchange = "hello_topic";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
//将队列hello_topic_c1 绑定到交换机hello_topic上
String queueName1 = "hello_topic_c1";
// 声明队列
channel.queueDeclare(queueName1, true, false, false, null);
// 绑定队列到交换机
String routingKey1 = "*.orange.*";
channel.queueBind(queueName1, exchange, routingKey1,null);
//将队列hello_topic_c2 绑定到交换机hello_topic上
String queueName2 = "hello_topic_c2";
// 声明队列
channel.queueDeclare(queueName2, false, false, false, null);
// 绑定队列到交换机
String routingKey2 = "lazy.#";
channel.queueBind(queueName2, exchange, routingKey2,null);
}
运行后可以看到队列创建成功,
点击队列,查看队列信息,可以看到队列c1 和 c2都绑定到了hello_topic交换机上,路由键分别为lazy.#和*.orange.*。当我们发送
lazy.aa、lazy.aa.bb等这种路由键的消息,会被路由到队列c1。
aa.orange.bb、cc.orange.aa 等这种路由键的消息,会被路由到队列c2。
定义两个消费者,1个监听队列hello_topic_c1 、1个监听队列hello_topic_c2 并运行。
//消费者1
@Slf4j
public class Consumer1 {
public static void main(String[] argv) throws Exception {
String queueName = "hello_topic_c1";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
// 定义队列的消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
// 获取消息,并且处理,这个方法类似事件监听,如果有消息的时候,会被自动调用
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
// body 即消息体
String msg = new String(body);
log.debug("Consumer1 consume msg:{}",msg);
}
};
// 监听队列,自动返回完成
channel.basicConsume(queueName, true, consumer);
}
}
// 消费者2
@Slf4j
public class Consumer2 {
public static void main(String[] argv) throws Exception {
String queueName = "hello_topic_c2";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
// 定义队列的消费者
DefaultConsumer consumer = new DefaultConsumer(channel) {
// 获取消息,并且处理,这个方法类似事件监听,如果有消息的时候,会被自动调用
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
// body 即消息体
String msg = new String(body);
log.debug("Consumer2 consume msg:{}",msg);
}
};
// 监听队列,自动返回完成
channel.basicConsume(queueName, true, consumer);
}
}
发送消息:这里发送routing key 符合lazy.#规则的两条消息以及符合*.orange.*规则的两条消息
/**
* 生产者发送消息
* @throws Exception
*/
@Test
public void sendMessage() throws Exception {
String exchange = "hello_topic";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
// 发布消息到Exchange 指定路由键符合 *.orange.*
channel.basicPublish(exchange, "aa.orange.bb", null, "Less is more aa.orange.bb".getBytes());
channel.basicPublish(exchange, "cc.orange.dd", null, "Less is more cc.orange.dd".getBytes());
// 发布消息到Exchange 指定路由键符合lazy.#
channel.basicPublish(exchange, "lazy.aa", null, "Less is more lazy.aa".getBytes());
channel.basicPublish(exchange, "lazy.aa.bb", null, "Less is more lazy.aa.bb".getBytes());
channel.close();
connection.close();
}
可以看到消费者都收到了各自的消息:
消费者1:
消费者2:
详细源码地址
https://github.com/suzhe2018/rabbitmq-item