RabbitMQ 学习笔记 -- 06 Topic 交换机

534 阅读5分钟

一、介绍

上一章说到直连交换机可以基于路由键后进行有选择性接收消息的能力。但是它仍然有局限性,它不能实现多重条件的路由。

更加灵活的主题交换机:Topic

使用主题交换机时,不能使用任意写法的路由键,路由键的形式应该是由点分割的单词。用什么词都可以,通常都是能表明意义的。字数大小最大限制在255字节

使用主题交换机定义路由键需要注意两点

  1. * 星号代表一个单词
  2. # 井号代表0个或多个单词
topic_exchange
topic_exchange

这里举个栗子,主题交换机接收描述产品的消息。这个消息将会和由3个单词2个点构成的路由键一起发送。第一个单词描述品牌,第二个单词掉描述产品类型,第三个单词描述颜色。

创建三种绑定,队列 Tom 和键 *.phone.*绑定,队列 Jerry*.*.greenapple.# 绑定

三种绑定关系的概述为

  1. Tom 对手机感兴趣
  2. Jerry 喜欢绿色和苹果品牌的产品
  • 路由键为 apple.phone.green 的消息将会被传递到 TomJerry 这两个队列
  • 路由键为 mi.phone.yellow 的消息将会被传递到 Tom 队列
  • 路由键为 apple.watch.green 的消息将会被传递到 Jerry 队列
  • 路由键为 apple apple.laptop apple.mac.red.china 的消息都会传递到 Jerry 队列上,因为匹配到了 apple.# 这个规则上
  • 路由键为 mi.watch.red Lenovo.laptop.black 的消息会被丢弃,因为不管哪个队列都匹配不上

主题交换机是非常强大的,为啥这么膨胀?
1.当一个队列的绑定键为 #(井号) 的时候,这个队列将会无视消息的路由键,接收所有的消息。
2.当 * (星号) 和 # (井号) 这两个特殊字符都未在绑定键中出现的时候,此时主题交换机就拥有的直连交换机的行为。
所以主题交换机也就实现了扇形交换机的功能,和直连交换机的功能。

二、web 控制台操作

创建交换机

创建交换机
创建交换机

创建队列 Tom、 Jerry

创建队列 Tom
创建队列 Tom
创建队列 Jerry
创建队列 Jerry

绑定队列,填写相应的路由键,最终为:

路由绑定
路由绑定

我们在交换机中发布一条消息。指定一个路由键

发送信息至交换机 rabbit_exchange_topic,路由键为 mi.phone.green
发送信息至交换机 rabbit_exchange_topic,路由键为 mi.phone.green

这时候两条队列都收到了信息

两个队列都收到了信息
两个队列都收到了信息
Jerry 队列查看
Jerry 队列查看

三、代码方式:

声明队列,交换机,路由绑定

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Demo_05_Config {
    @Bean
    public Queue queueTom() {
        return new Queue("Tom");
    }
    @Bean
    public Queue queueJerry() {
        return new Queue("Jerry");
    }
    // 声明 topic 交换机
    @Bean
    public TopicExchange topicExchange() {
        return new TopicExchange("rabbit_exchange_topic");
    }
    @Bean
    public Binding bindingTom() {
        String routingKey = "*.phone.*";
        return BindingBuilder.bind(queueTom()).to(topicExchange()).with(routingKey);
    }
    @Bean
    public Binding bindingJerry1() {
        String routingKey = "*.*.green";
        return BindingBuilder.bind(queueJerry()).to(topicExchange()).with(routingKey);
    }
    @Bean
    public Binding bindingJerry2() {
        String routingKey = "apple.#";
        return BindingBuilder.bind(queueJerry()).to(topicExchange()).with(routingKey);
    }
}

消费者

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

@Component
public class Demo_05_Consumer {
    @RabbitListener(queues = "Tom")
    public void receive(String msg, @Header(value = AmqpHeaders.RECEIVED_ROUTING_KEY) String routingKey) {
        System.out.println("Tom 收到产品信息:" + msg + ",路由键为:【" + routingKey + "】");
    }
    @RabbitListener(queues = "Jerry")
    public void receive2(String msg, @Header(value = AmqpHeaders.RECEIVED_ROUTING_KEY) String routingKey) {
        System.out.println("Jerry 收到产品信息:" + msg + ",路由键为:【" + routingKey + "】");
    }
}

生产者:

@Test
public void demo_05_Producer() {
    String exchange = "rabbit_exchange_topic";

    String routingKey1 = "apple.phone.green";
    String routingKey2 = "mi.phone.red";
    String routingKey3 = "apple.watch.green";
    String routingKey4 = "apple.laptop";
    String routingKey5 = "mi.watch.red";

    String msg1 = "苹果手机(绿色)";
    String msg2 = "小米手机(黄色)";
    String msg3 = "苹果手表(绿色)";
    String msg4 = "苹果电脑";
    String msg5 = "小米手表(红色)";

    rabbitTemplate.convertAndSend(exchange, routingKey1, msg1);
    rabbitTemplate.convertAndSend(exchange, routingKey2, msg2);
    rabbitTemplate.convertAndSend(exchange, routingKey3, msg3);
    rabbitTemplate.convertAndSend(exchange, routingKey4, msg4);
    rabbitTemplate.convertAndSend(exchange, routingKey5, msg5);
}

输出:

Tom 收到产品信息:苹果手机(绿色),路由键为:【apple.phone.green
Jerry 收到产品信息:苹果手机(绿色),路由键为:【apple.phone.green
Jerry 收到产品信息:苹果手表(绿色),路由键为:【apple.watch.green
Tom 收到产品信息:小米手机(黄色),路由键为:【mi.phone.red
Jerry 收到产品信息:苹果电脑,路由键为:【apple.laptop

可以看到,msg1 的信息匹配到了两个队列都获取到了相同的信息,msg5 的信息因为没有匹配到路由键被丢弃了,