RabbitMQ教程-Topic Exchange類型的基本使用demo

echo編輯整理,歡迎轉載,轉載請聲明文章來源。歡迎添加echo微信(微信號:t2421499075) 交流學習。


上兩篇文章中,我們使用Direct Exchange和Fanout Exchange類型推送了消息,但是我們發現這兩種類型在某些情況下並不適合,比如:我們MQ中有一百個不同隊列訂閱了我們的某個生產者,但是在某一次的時候,我們生產者只希望其中一部分對了能接受消息,那麼我們的Fanout Exchange直接廣播就會造成信息資源浪費,如果我們選擇Direct Exchange的時候,那我們要發送給對應的幾十個隊列就會要不斷設置,重複工作很多,也很容易出錯。但是要是能夠根據我們的隊列RoutingKey來模糊匹配是不是很我們的問題就完美解決了啊。本文就是講解這種模式

使用Topic Exchange根據規則推送一條消息

  • 準備工作 既然我們要根據規則推送給某一批隊列,我們要先建立一批隊列,指定路由器類型爲Topic Exchange,然後我們使用規則定義routing key。我們這裏準備了三個隊列

在這裏插入圖片描述

並通過routing key進行綁定到topic類型的Exchange上

在這裏插入圖片描述

routing key作用解析

routing key的命名是我們Topic Exchange類型的最關鍵部分,在推送消息的時候,如果是使用topic類型的Exchange可以直接不指定隊列,所以這個時候routing key就成爲了我們推送消息的關鍵。爲了消息能夠更好的推送接受,在這個地方我們肯定要規範的定義routing kye的名稱。在我們這裏,我們看了總共有三個routing key

  • com.echo.* :當推送消息時routing key爲com.echo.任意字符的時候,隊列queue_topic1對應的隊列一定能接受到消息
  • com.echo.level2 :當推送消息時routing key爲com.echo.level2,隊列queue_topic2對應的隊列纔會接受到消息
  • # :當推送消息時routing key爲任意值,隊列queue_topic2對應的隊列都能接受到消息

其中 * 匹配任意一個單詞,# 匹配零個或者多個單詞。

代碼案例

package com.example.demo;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @author echo
 * @date 2021-01-14 14:35
 */
public class TopicProductTest {

    private static final String EXCHANGE_NAME = "exchange_topic";
    private static final String ROUTING_KEY = "com.echo.level2";
    private static final String IP_ADDRESS = "192.168.230.131";
    private static final int PORT = 5672;


    public static void main(String[] args) throws IOException, TimeoutException {

        // 創建連接工廠
        ConnectionFactory factory = new ConnectionFactory();
        // 設置RabbitMQ的鏈接參數
        factory.setHost(IP_ADDRESS);
        factory.setPort(PORT);
        factory.setUsername("echo");
        factory.setPassword("123456");
        // 和RabbitMQ建立一個鏈接
        Connection connection = factory.newConnection();
        // 創建一個頻道
        Channel channel = connection.createChannel();
        // 創建一個 type="direct" 、持久化的、非自動刪除的交換器
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC, true, false, null);
        // 發送一條持久化的消息: topic hello world !
        String message = "topic hello world !";
        channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
        // 關閉資源
        channel.close();
        connection.close();

    }

}

按照上面routing key的作用,我們這個實例推送的消息,對應的三個隊列應該都會受到消息,我們運行了看看結果

在這裏插入圖片描述

最終結果和我們的作用域的描述符合

  • 我們還可以使用消費者來驗證一下 消費者代碼
package com.example.demo;

import com.rabbitmq.client.*;
import lombok.SneakyThrows;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author tang.sl
 * @date 2021-01-14 15:05
 */
public class TopicConsumerTest {

    private static final String EXCHANGE_NAME = "exchange_topic";
    private static final String QUEUE_NAME = "queue_topic1";
    private static final String IP_ADDRESS = "192.168.230.131";
    private static final int PORT = 5672;

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        // 設置RabbitMQ的鏈接參數
        factory.setUsername("echo");
        factory.setPassword("123456");
        factory.setPort(PORT);
        factory.setHost(IP_ADDRESS);

        // 和RabbitMQ建立一個鏈接
        Connection connection = factory.newConnection();
        final Channel channel = connection.createChannel();
        //聲明交換機 Fanout模式
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC, true, false, null);
        //進行綁定,指定消費那個隊列
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "", null);
        Consumer consumer = new DefaultConsumer(channel) {
            @SneakyThrows
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) {
                System.out.println("recv message: " + new String(body));
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                channel.basicAck(envelope.getDeliveryTag(), false);
            }
        };
        channel.basicConsume(QUEUE_NAME, consumer);
        //等待回調函數執行完畢之後 關閉資源
        TimeUnit.SECONDS.sleep(5);
        channel.close();
        connection.close();
    }
}

運行之後結果一致

在這裏插入圖片描述

總結

topic能夠對指定的一系列或者說一堆的隊列發送消息,關鍵就是靠routing key的*和#這兩個通配符的匹配作用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章