SpringBoot 整合 RabbitMQ 學習筆記

RabbitMQ Linwei Note

轉載說明:

https://blog.csdn.net/qq_35387940/article/details/100514134

https://www.cnblogs.com/xifengxiaoma/p/11121355.html

一、RabbitMQ 介紹

1. RabbitMQ的安裝

目前主要先了解其使用,因此安裝在此先略過

2. 理論及名詞介紹

2.1 整體介紹

RabbitMQ是一個開源的AMQP實現,服務器端用 Erlang 語言編寫,支持多種客戶端,如:Java、Python、Ruby、.NET、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用於在分佈式系統中存儲轉發消息,具有很高的易用性和可用性。

在安裝完rabbitMq後,輸入http://ip:15672/ ,是可以看到一個簡單後臺管理界面的。

在控制檯裏可以手動創建虛擬host,創建用戶,分配權限,創建交換機,創建隊列等等,還有查看隊列消息,消費效率,推送效率等等。

黃色的圈圈就是我們的消息推送服務,將消息推送到 中間方框裏面也就是 rabbitMq的服務器,然後經過服務器裏面的交換機、隊列等各種關係(後面會詳細講)將數據處理入列後,最終右邊的藍色圈圈消費者獲取對應監聽的消息。

Exchange Type交換機的類別

  • Direct Exchange 直連交換機

    direct類型的Exchange路由規則也很簡單,它會把消息路由到那些binding key與routing key完全匹配的Queue中。

    當生產者(P)發送消息時Rotuing key=booking時,這時候將消息傳送給Exchange,Exchange獲取到生產者發送過來消息後,會根據自身的規則進行與匹配相應的Queue,這時發現Queue1和Queue2都符合,就會將消息傳送給這兩個隊列,如果我們以Rotuing key=create和Rotuing key=confirm發送消息時,這時消息只會被推送到Queue2隊列中,其他Routing Key的消息將會被丟棄。

  • Fanout Exchange 扇型交換機

    這個交換機沒有路由鍵概念,就算你綁了路由鍵也是無視的。 這個交換機在接收到消息後,會直接轉發到綁定到它上面的所有隊列中。

  • Topic Exchange 主題交換機

    前面提到的direct規則是嚴格意義上的匹配,換言之Routing Key必須與Binding Key相匹配的時候纔將消息傳送給Queue,那麼topic這個規則就是模糊匹配,可以通過通配符滿足一部分規則就可以傳送。

    通過通配符 *,# 來綁定鍵; * 星號表示一個佔位符,# 表示0個或多個佔位符,例如:

    隊列Q1 綁定鍵爲 .TT. 隊列Q2綁定鍵爲 TT.#
    如果一條消息攜帶的路由鍵爲 A.TT.B,那麼隊列Q1將會收到;
    如果一條消息攜帶的路由鍵爲TT.AA.BB,那麼隊列Q2將會收到;

    當一個隊列的綁定鍵爲 "#"(井號) 的時候,這個隊列將會無視消息的路由鍵,接收所有的消息。
    當 * (星號) 和 # (井號) 這兩個特殊字符都未在綁定鍵中出現的時候,此時主題交換機就擁有的直連交換機的行爲。
    所以主題交換機也就實現了扇形交換機的功能,和直連交換機的功能。

2.2 名詞介紹

  • ConnectionFactory、Connection、Channel

    ConnectionFactory、Connection、Channel都是RabbitMQ對外提供的API中最基本的對象。Connection是RabbitMQ的socket鏈接,它封裝了socket協議相關部分邏輯。ConnectionFactory爲Connection的製造工廠。 Channel是我們與RabbitMQ打交道的最重要的一個接口,我們大部分的業務操作是在Channel這個接口中完成的,包括定義Queue、定義Exchange、綁定Queue與Exchange、發佈消息等。

  • Queue

    Queue(隊列)是RabbitMQ的內部對象,用於存儲消息。

    RabbitMQ中的消息都只能存儲在Queue中,生產者(下圖中的P)生產消息並最終投遞到Queue中,消費者(下圖中的C)可以從Queue中獲取消息並消費。

  • Message acknowledgment

    在實際應用中,可能會發生消費者收到Queue中的消息,但沒有處理完成就宕機(或出現其他意外)的情況,這種情況下就可能會導致消息丟失。爲了避免這種情況發生,我們可以要求消費者在消費完消息後發送一個回執給RabbitMQ,RabbitMQ收到消息回執(Message acknowledgment)後纔將該消息從Queue中移除;如果RabbitMQ沒有收到回執並檢測到消費者的RabbitMQ連接斷開,則RabbitMQ會將該消息發送給其他消費者(如果存在多個消費者)進行處理。這裏不存在timeout概念,一個消費者處理消息時間再長也不會導致該消息被髮送給其他消費者,除非它的RabbitMQ連接斷開。 這裏會產生另外一個問題,如果我們的開發人員在處理完業務邏輯後,忘記發送回執給RabbitMQ,這將會導致嚴重的bug——Queue中堆積的消息會越來越多;消費者重啓後會重複消費這些消息並重復執行業務邏輯。

  • Message durability

    如果我們希望即使在RabbitMQ服務重啓的情況下,也不會丟失消息,我們可以將Queue與Message都設置爲可持久化的(durable),這樣可以保證絕大部分情況下我們的RabbitMQ消息不會丟失。但依然解決不了小概率丟失事件的發生(比如RabbitMQ服務器已經接收到生產者的消息,但還沒來得及持久化該消息時RabbitMQ服務器就斷電了),如果我們需要對這種小概率事件也要管理起來,那麼我們要用到事務。由於這裏僅爲RabbitMQ的簡單介紹,所以這裏將不講解RabbitMQ相關的事務。

  • Exchange

    生產者產生的消息並不是直接發送給消息隊列Queue的,而是要經過Exchange(交換器),由Exchange再將消息路由到一個或多個Queue,當然這裏還會對不符合路由規則的消息進行丟棄掉,這裏指的是後續要談到的Exchange Type。那麼Exchange是怎樣將消息準確的推送到對應的Queue的呢?那麼這裏的功勞最大的當屬Binding,RabbitMQ是通過Binding將Exchange和Queue鏈接在一起,這樣Exchange就知道如何將消息準確的推送到Queue中去。

二、RabbitMQ的使用

1. 以Topic交換機爲例(實例)

1.1 加依賴

新建springboot項目,修改pom添加rabbit依賴

<!--rabbitmq-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

1.2 加配置

配置rabbit服務器連接信息

server:
  port: 8080

spring:
  application:
    name: rabbitmq-demo
    
#  rabbit服務器配置
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: test
    password: test123

1.3 添加配置類-定義QueueExchange

定義的Queue和Exchange,如果在RabbitMQ控制檯中沒有,會自動創建;

package com.linwei.rabbitmq.demo.config;

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 TopicRabbitConfig {

    public static final String QUEUE_NAME = "topic.queue.test01";
    public static final String EXCHANGE_NAME = "topicExchange";

    /**
     * 定義隊列:隊列名 topic.queue.test01
     * durable持久化設置爲false,默認爲true;
     * @return
     */
    @Bean
    public Queue taskQueue(){
        return new Queue(QUEUE_NAME,false);
    }

    /**
     * 定義交換機, 參數是交換機的名字
     * @return
     */
    @Bean
    public TopicExchange exchange(){
        return new TopicExchange(EXCHANGE_NAME);
    }

    /**
     * 將隊列與交換機綁定, 並指定Routing Key
     * @return
     */
    @Bean
    Binding bindingExchange(){
        return BindingBuilder.bind(taskQueue()).to(exchange()).with(QUEUE_NAME);
    }
}

1.4 新建controller用來發送消息(生產者)

package com.linwei.rabbitmq.demo.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@RestController
public class RabbitTestController {

    //使用RabbitTemplate,這提供了接收/發送等等方法
    @Autowired
    RabbitTemplate rabbitTemplate ;

    @RequestMapping("/sendmessage")
    public String sendTopicMessage(){
        String message = "This is test message by Springboot demo ."
                + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        log.info("--->send message: {}",message);
        // 發送消息(交換機, routingKey, 消息)
        rabbitTemplate.convertAndSend("topicExchange","topic.queue.test01",message);
        return "ok";
    }

}

1.5 定義消費者Consumer

@RabbitListener 指定監聽的隊列;

@RabbitHandler 接收消息後的處理方法;

package com.linwei.rabbitmq.demo.consumer;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "topic.queue.test01")
public class TopicConsumerTest {

    /**
     * 消息消費
     * @RabbitHandler 代表此方法爲接受到消息後的處理方法
     */
    @RabbitHandler
    public void received(String msg){
        System.out.println("--->Consumer消費消息: "+ msg);
    }
}

1.6 測試發送消息

發送get請求http://localhost:8080/sendmessage 進行消息發送;

--->send message: This is test message by Springboot demo .2021-08-24 16:37:03.195
--->send message: This is test message by Springboot demo .2021-08-24 16:37:05.672
--->send message: This is test message by Springboot demo .2021-08-24 16:37:05.871

登錄Rabbit控制檯,可以看到隊列topic.queue.test01裏有三條待處理的消息;

下面打印的是消費者接收並處理的信息:(消息被消費後,上面控制檯裏的數量會被置0,所以上面total顯示的是待處理的消息總數,而不是歷史消息總數)

--->Consumer消費消息: This is test message by Springboot demo .2021-08-24 16:37:03.195
--->Consumer消費消息: This is test message by Springboot demo .2021-08-24 16:37:05.672
--->Consumer消費消息: This is test message by Springboot demo .2021-08-24 16:37:05.871

1.7 補充測試

上面已經定義了一個消費者TopicConsumerTest , 如果我再定義一個監聽相同queue的消費者會怎麼樣呢?

@Component
@RabbitListener(queues = "topic.queue.test01")
public class TopicConsumerTest2 {

    /**
     * 消息消費
     * @RabbitHandler 代表此方法爲接受到消息後的處理方法
     */
    @RabbitHandler
    public void received(String msg){
        System.out.println("--->Consumer02消費消息: "+ msg);
    }
}

實驗效果:
如果隊列裏有消息,每次只會被一個消費者消費,如果拼命刷新頁面,即模擬生產者往隊列裏發送消息,通過控制檯打印可以發現,消費者02可能會被觸發;所以,如果有多個消費者監聽同一個隊列,多個消費者相當於多實例,一個消息只會被一個消費者進行消費,不會存在重複消費的情況。
有意思的是,兩個消費者是輪流消費的,這裏面應該是採用了輪詢的方式進行負載了。

--->Consumer02消費消息: This is test message by Springboot demo .2021-08-25 15:58:25.785
--->Consumer消費消息: This is test message by Springboot demo .2021-08-25 15:58:25.944
--->Consumer02消費消息: This is test message by Springboot demo .2021-08-25 15:58:26.088
--->Consumer消費消息: This is test message by Springboot demo .2021-08-25 15:58:26.257
--->Consumer02消費消息: This is test message by Springboot demo .2021-08-25 15:58:26.443

在RabbitMQ控制檯裏也能夠看到隊列的消費者的個數:
image

2. direct 直連交換機(網例)

direct類型的Exchange路由規則很簡單,它會把消息路由到那些binding key與routing key完全匹配的Queue中。

2.1 新建一個RabbitMQ配置類,並添加一個demoQueue隊列

package com.louis.springboot.demo.config;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfig {

    /**
     * 定義demoQueue隊列
     * @return
     */
    @Bean
    public Queue demoString() {
        return new Queue("demoQueue");
    }
    
}

2.2 編寫生產者發送消息

編寫一個消息發佈者,並編寫一個發送方法,通過AmqpTemplate往"demoQueue"發送消息。

RabbitProducer.java

package com.louis.springboot.demo.mq;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class RabbitProducer {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void sendDemoQueue() {
        Date date = new Date();
        String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
        System.out.println("[demoQueue] send msg: " + dateString);  
        // 第一個參數爲剛剛定義的隊列名稱
        this.rabbitTemplate.convertAndSend("demoQueue", dateString);
    }
}

2.3 編寫一個消息消費者

編寫一個消息消費者,通過@RabbitListener(queues = "demoQueue")註解監聽"demoQueue"隊列,並用@RabbitHandler註解相關方法,這樣在在隊列收到消息之後,交給@RabbitHandler註解的方法進行處理。

package com.louis.springboot.demo.mq;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;


@Component
@RabbitListener(queues = "demoQueue")
public class DemoQueueConsumer {

    /**
     * 消息消費
     * @RabbitHandler 代表此方法爲接受到消息後的處理方法
     */
    @RabbitHandler
    public void recieved(String msg) {
        System.out.println("[demoQueue] recieved message: " + msg);
    }

}

2.4 編寫測試controller

編寫一個控制器,注入RabbitProducer調用相關消息發送方法,方便通過接口觸發消息發送。

package com.louis.springboot.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.louis.springboot.demo.mq.RabbitProducer;

@RestController
public class RabbitMqController {

    @Autowired
    private RabbitProducer rabbitProducer;

    @GetMapping("/sendDemoQueue")
    public Object sendDemoQueue() {
        rabbitProducer.sendDemoQueue();
        return "success";
    }
}

2.5 觀察輸出

調用兩次sendDemoQueue接口,在控制檯可以看到我們輸出的信息,說明消息已經成功發送並被消費。

[demoQueue] send msg: 2019-58-183 04:07:38
[demoQueue] recieved message: 2019-58-183 04:07:38
[demoQueue] send msg: 2019-01-183 05:07:05
[demoQueue] recieved message: 2019-01-183 05:07:05

3. fanout 扇形交換機

fanout類型的Exchange路由規則也非常簡單,它會把所有發送到該Exchange的消息路由到所有與它綁定的Queue中。

Fanout其實就是廣播模式,只要跟它綁定的隊列都會通知並且接受到消息。

3.1 修改配置類

RabbitConfig.java

	@Bean
    public Queue fanoutA() {
        return new Queue("fanout.a");
    }

    @Bean
    public Queue fanoutB() {
        return new Queue("fanout.b");
    }

    @Bean
    public Queue fanoutC() {
        return new Queue("fanout.c");
    }

    /**
     * 定義個fanout交換器
     * @return
     */
    @Bean
    FanoutExchange fanoutExchange() {
        // 定義一個名爲fanoutExchange的fanout交換器
        return new FanoutExchange("fanoutExchange");
    }

    /**
     * 將定義的fanoutA隊列與fanoutExchange交換機綁定
     * @return
     */
    @Bean
    public Binding bindingExchangeWithA() {
        return BindingBuilder.bind(fanoutA()).to(fanoutExchange());
    }

    /**
     * 將定義的fanoutB隊列與fanoutExchange交換機綁定
     * @return
     */
    @Bean
    public Binding bindingExchangeWithB() {
        return BindingBuilder.bind(fanoutB()).to(fanoutExchange());
    }

    /**
     * 將定義的fanoutC隊列與fanoutExchange交換機綁定
     * @return
     */
    @Bean
    public Binding bindingExchangeWithC() {
        return BindingBuilder.bind(fanoutC()).to(fanoutExchange());
    }

3.2 修改生產者

然後我們在RabbitProducer中添加一個sendFanout方法,用來向fanout隊列發送消息。

RabbitProducer.java

public void sendFanout() {
    Date date = new Date();
    String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
    System.out.println("[fanout] send msg:" + dateString);
    // 注意 第一個參數是我們交換機的名稱 ,第二個參數是routerKey 我們不用管空着就可以,第三個是你要發送的消息
    this.rabbitTemplate.convertAndSend("fanoutExchange", "", dateString);
}

3.2 新增的消費者

接着針對三個廣播隊列分別編寫一個消息消費者,指定隊列和處理函數。

FanoutAConsumer.java

package com.louis.springboot.demo.mq;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "fanout.a")
public class FanoutAConsumer {

    /**
     * 消息消費
     * @RabbitHandler 代表此方法爲接受到消息後的處理方法
     */
    @RabbitHandler
    public void recieved(String msg) {
        System.out.println("[fanout.a] recieved message: " + msg);
    }
}

FanoutBConsumer.java

package com.louis.springboot.demo.mq;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "fanout.b")
public class FanoutBConsumer {

    /**
     * 消息消費
     * @RabbitHandler 代表此方法爲接受到消息後的處理方法
     */
    @RabbitHandler
    public void recieved(String msg) {
        System.out.println("[fanout.b] recieved message: " + msg);
    }
}

FanoutCConsumer.java

package com.louis.springboot.demo.mq;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "fanout.c")
public class FanoutCConsumer {

    /**
     * 消息消費
     * @RabbitHandler 代表此方法爲接受到消息後的處理方法
     */
    @RabbitHandler
    public void recieved(String msg) {
        System.out.println("[fanout.c] recieved message: " + msg);
    }
}

3.4 新增測試controller

RabbitMqController.java

@GetMapping("/sendFanout")
public Object sendFanout() {
    rabbitProducer.sendFanout();
    return "success";
}

3.5 觀察輸出

重新啓動應用,調用sendFanout接口,通過控制檯可以看到消息發送之後,a, b, c三個隊列都收到了消息。

[fanout] send msg:2019-47-183 05:07:12
[fanout.c] recieved message: 2019-47-183 05:07:12
[fanout.b] recieved message: 2019-47-183 05:07:12
[fanout.a] recieved message: 2019-47-183 05:07:12

4. topic 主題交換機

利用topic模式可以實現模糊匹配,同樣的,在RabbitConfig中配置topic隊列跟交換器。

4.1 修改配置類

topicA的key爲topic.msg 那麼他只會接收包含topic.msg的消息

topicB的key爲topic.#那麼他只會接收topic開頭的消息

topicC的key爲topic.*.z那麼他只會接收topic.x.z這樣格式的消息

RabbitConfig.java

//=================== topic主題模式  ====================

    @Bean
    public Queue topiocA() {
        return new Queue("topic.a");
    }

    @Bean
    public Queue topicB() {
        return new Queue("topic.b");
    }

    @Bean
    public Queue topicC() {
        return new Queue("topic.c");
    }

    /**
     * 定義個topic交換器
     * @return
     */
    @Bean
    TopicExchange topicExchange() {
        // 定義一個名爲fanoutExchange的fanout交換器
        return new TopicExchange("topicExchange");
    }

    /**
     * 將定義的topicA隊列與topicExchange交換機綁定;
     * 並指定routingKey爲topic.msg,將消息發給topic.msg匹配的Queue
     * @return
     */
    @Bean
    public Binding bindingTopicExchangeWithA() {
        return BindingBuilder.bind(topiocA()).to(topicExchange()).with("topic.msg");
    }

    /**
     * 將定義的topicB隊列與topicExchange交換機綁定
     * @return
     */
    @Bean
    public Binding bindingTopicExchangeWithB() {
        return BindingBuilder.bind(topicB()).to(topicExchange()).with("topic.#");
    }

    /**
     * 將定義的topicC隊列與topicExchange交換機綁定
     * @return
     */
    @Bean
    public Binding bindingTopicExchangeWithC() {
        return BindingBuilder.bind(topicC()).to(topicExchange()).with("topic.*.z");
    }

4.2 修改生產者

RabbitProducer.java

public void sendTopicTopicAB() {
    Date date = new Date();
    String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
    dateString = "[topic.msg] send msg:" + dateString;
    System.out.println(dateString);
    // 注意 第一個參數是我們交換機的名稱 ,第二個參數是routerKey topic.msg,第三個是你要發送的消息
    // 這條信息將會被 topic.a  topic.b接收
    this.rabbitTemplate.convertAndSend("topicExchange", "topic.msg", dateString);
}

public void sendTopicTopicB() {
    Date date = new Date();
    String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
    dateString = "[topic.good.msg] send msg:" + dateString;
    System.out.println(dateString);
    // 注意 第一個參數是我們交換機的名稱 ,第二個參數是routerKey ,第三個是你要發送的消息
    // 這條信息將會被topic.b接收
    this.rabbitTemplate.convertAndSend("topicExchange", "topic.good.msg", dateString);
}

public void sendTopicTopicBC() {
    Date date = new Date();
    String dateString = new SimpleDateFormat("YYYY-mm-DD hh:MM:ss").format(date);
    dateString = "[topic.m.z] send msg:" + dateString;
    System.out.println(dateString);
    // 注意 第一個參數是我們交換機的名稱 ,第二個參數是routerKey ,第三個是你要發送的消息
    // 這條信息將會被topic.b、topic.c接收
    this.rabbitTemplate.convertAndSend("topicExchange", "topic.m.z", dateString);
}

4.3 添加隊列消費者

接着針對三個主題隊列編寫對應的消息消費者。

TopicAConsumer.java

package com.louis.springboot.demo.mq;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "topic.a")
public class TopicAConsumer {

    /**
     * 消息消費
     * @RabbitHandler 代表此方法爲接受到消息後的處理方法
     */
    @RabbitHandler
    public void recieved(String msg) {
        System.out.println("[topic.a] recieved message:" + msg);
    }
}

TopicBConsumer.java

package com.louis.springboot.demo.mq;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "topic.b")
public class TopicBConsumer {

    /**
     * 消息消費
     * @RabbitHandler 代表此方法爲接受到消息後的處理方法
     */
    @RabbitHandler
    public void recieved(String msg) {
        System.out.println("[topic.b] recieved message:" + msg);
    }
}

TopicCConsumer.java

package com.louis.springboot.demo.mq;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "topic.c")
public class TopicCConsumer {

    /**
     * 消息消費
     * @RabbitHandler 代表此方法爲接受到消息後的處理方法
     */
    @RabbitHandler
    public void recieved(String msg) {
        System.out.println("[topic.c] recieved message:" + msg);
    }
}

4.4 修改controller

RabbitMqController.java

@GetMapping("/sendTopicTopicAB")
public Object sendTopicTopicAB() {
    rabbitProducer.sendTopicTopicAB();
    return "success";
}

@GetMapping("/sendTopicTopicB")
public Object sendTopicTopicB() {
    rabbitProducer.sendTopicTopicB();
    return "success";
}

@GetMapping("/sendTopicTopicBC")
public Object sendTopicTopicBC() {
    rabbitProducer.sendTopicTopicBC();
    return "success";
}

4.5 重啓測試

重啓應用,調用sendTopicTopicAB接口,經過匹配,route key爲“topic.msg”的消息被髮送到了topic.a和topic.b。

[topic.msg] send msg:2019-12-183 06:07:22
[topic.b] recieved message:[topic.msg] send msg:2019-12-183 06:07:22
[topic.a] recieved message:[topic.msg] send msg:2019-12-183 06:07:22

調用sendTopicTopicB接口,經過匹配,route key爲“topic.good.msg”的消息被髮送到了topic.b。

[topic.good.msg] send msg:2019-15-183 06:07:23
[topic.b] recieved message:[topic.good.msg] send msg:2019-15-183 06:07:23

調用sendTopicTopicBC接口,經過匹配,route key爲“topic.m.z”的消息被髮送到了topic.b和topic.c。

[topic.m.z] send msg:2019-16-183 06:07:09
[topic.b] recieved message:[topic.m.z] send msg:2019-16-183 06:07:09
[topic.c] recieved message:[topic.m.z] send msg:2019-16-183 06:07:09
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章