25《Spring Boot 入門教程》Spring Boot RabbitMQ 應(yīng)用場(chǎng)景

1. 前言

消息隊(duì)列是一個(gè)容器,可以對(duì)程序產(chǎn)生的消息進(jìn)行存儲(chǔ)。消息隊(duì)列的主要用途是削峰、異步、解耦,我們用一個(gè)實(shí)際場(chǎng)景來(lái)解釋下。

有一家果汁生產(chǎn)企業(yè),張三是采購(gòu)員,負(fù)責(zé)采購(gòu)水果;李四、趙五是配送員,分別負(fù)責(zé)將蘋果、香蕉配送到生產(chǎn)車間。

1.1 削峰

傳統(tǒng)模式下,張三采購(gòu)?fù)瓿?,回到公司后,?lián)系李四、趙五配送采購(gòu)的水果。但是隨著公司業(yè)務(wù)量大增,張三一次性采購(gòu)的水果,李四、趙五得需要幾天才能配送完。所以需要一個(gè)倉(cāng)庫(kù),張三采購(gòu)?fù)瓿芍苯臃诺絺}(cāng)庫(kù)里,李四、趙五慢慢從倉(cāng)庫(kù)取出配送。

此處的倉(cāng)庫(kù)就是消息隊(duì)列,張三是采購(gòu)消息的生產(chǎn)者,李四、趙五是消費(fèi)者。當(dāng)生產(chǎn)的消息太多時(shí),可以使用隊(duì)列削峰,這樣消費(fèi)者可以慢慢處理消息。

1.2 異步

傳統(tǒng)模式下,張三采購(gòu)?fù)瓿珊?,需要等待李四、趙五來(lái)取,實(shí)際上極大浪費(fèi)了張三的時(shí)間。如果直接放入倉(cāng)庫(kù),可以不必等待,直接進(jìn)行下面的工作。也就是說(shuō),張三與李四、趙五的工作是異步的,減少了等待時(shí)間。

1.3 解耦

之前張三采購(gòu)?fù)瓿珊?,有?zé)任通知李四、趙五來(lái)取。萬(wàn)一李四、趙五忘帶手機(jī),張三還得聯(lián)系領(lǐng)導(dǎo)協(xié)調(diào)處理,說(shuō)實(shí)話張三就是個(gè)大老粗,整天為這些破事煩得不行。

如果直接放入倉(cāng)庫(kù),張三根本不用管李四、趙五的事情,感覺愉快極了。張三與李四、趙五的工作不再互相依賴,都變得更加簡(jiǎn)單了,這就是解耦。

2. RabbitMQ 簡(jiǎn)介

RabbitMQ 是非常出名的消息中間件,遵循 AMQP 協(xié)議,可以跨平臺(tái)、跨語(yǔ)言使用。 RabbitMQ 具備低時(shí)延、高可用的特點(diǎn),還有簡(jiǎn)潔易用的可視化管理界面,所以本節(jié)我們使用 RabbitMQ 來(lái)進(jìn)行消息隊(duì)列技術(shù)的演示。

5ed1ca7d09a9342506440331.jpg

RabbitMQ 可視化管理界面

3. Spring Boot 實(shí)現(xiàn)

我們就針對(duì)上面的場(chǎng)景,使用 Spring Boot ,結(jié)合 RabbitMQ 來(lái)具體實(shí)現(xiàn)下水果采購(gòu)、配送的管理。

3.1 使用 Spring Initializr 創(chuàng)建項(xiàng)目

Spring Boot 版本選擇 2.2.5 ,Group 為 com.imooc , Artifact 為 spring-boot-rabbitmq,生成項(xiàng)目后導(dǎo)入 Eclipse 開發(fā)環(huán)境。

3.2 引入項(xiàng)目依賴

我們引入 Web 項(xiàng)目依賴與 AMQP 消息隊(duì)列依賴。

實(shí)例:

        <!-- Web 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- AMQP 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
代碼塊12345678910

3.3 配置 RabbitMQ 連接信息

項(xiàng)目創(chuàng)建后,通過(guò) applicaiton.properties 配置 RabbitMQ 的鏈接信息。

實(shí)例:

#地址
spring.rabbitmq.host=127.0.0.1
#端口 默認(rèn)5672
spring.rabbitmq.port=5672
#用戶名
spring.rabbitmq.username=guest
#密碼
sprng.rabbitmq.password=guest
代碼塊12345678

3.4 配置隊(duì)列

首先配置兩個(gè)隊(duì)列,存儲(chǔ)蘋果采購(gòu)消息、香蕉采購(gòu)消息。

實(shí)例:

/**
 * 消息隊(duì)列配置類
 */
@Configuration
public class RabbitConfig {
    /**
     * 蘋果采購(gòu)消息隊(duì)列
     */
    @Bean
    public Queue appleQueue() {
        return new Queue("apple-queue");
    }

    /**
     * 香蕉采購(gòu)消息隊(duì)列
     */
    @Bean
    public Queue bananaQueue() {
        return new Queue("banana-queue");
    }
}
代碼塊123456789101112131415161718192021

3.5 配置交換機(jī)和綁定

如果消息直接發(fā)到隊(duì)列的話,不夠靈活, RabbitMQ 提供了交換機(jī)與綁定機(jī)制。

消息發(fā)送給交換機(jī),交換機(jī)可以靈活地與隊(duì)列進(jìn)行綁定,這樣消息就可以通過(guò)多種方式進(jìn)入隊(duì)列了。

實(shí)例:

    /**
     * 配置交換機(jī)
     */
    @Bean
    TopicExchange exchangeTopic() {
        return new TopicExchange("exchange-topic");
    }

    /**
     * 交換機(jī)綁定蘋果采購(gòu)消息隊(duì)列
     */
    @Bean
    Binding bindAppleQueue() {
        return BindingBuilder.bind(appleQueue()).to(exchangeTopic()).with("#.apple.#");
    }

    /**
     * 交換機(jī)綁定香蕉采購(gòu)消息隊(duì)列
     */
    @Bean
    Binding bindBananaQueue() {
        return BindingBuilder.bind(bananaQueue()).to(exchangeTopic()).with("#.banana.#");
    }

我們來(lái)詳細(xì)解釋下交換機(jī)與綁定的運(yùn)行機(jī)制。

  1. 我們配置了一個(gè)交換機(jī) exchangeTopic ,它可以接收消息。
  2. 交換機(jī) exchangeTopic 綁定了兩個(gè)隊(duì)列,分別是 appleQueue 和 bananaQueue ,說(shuō)明這兩個(gè)隊(duì)列在關(guān)注該交換機(jī)收到的消息。
  3. 那么交換機(jī) exchangeTopic 收到的消息到底會(huì)進(jìn)入哪個(gè)隊(duì)列呢,我們發(fā)現(xiàn)交換機(jī)的類型是 TopicExchange ,說(shuō)明該交換機(jī)是話題交換機(jī),隊(duì)列應(yīng)該是獲取其感興趣的話題相關(guān)的消息。
  4. 當(dāng) appleQueue 隊(duì)列綁定到交換機(jī)時(shí),with("#.apple.#") 就表示 appleQueue 關(guān)心的是 apple 相關(guān)的話題;而 bananaQueue 關(guān)心的是 banana 相關(guān)的話題。
  5. 所以可以推斷出,消息在發(fā)送時(shí),可以指定話題相關(guān)的信息,以便消息能被關(guān)注該話題的隊(duì)列接收。

經(jīng)過(guò)上面的分析,我們就知道了消息發(fā)送時(shí)通過(guò)攜帶話題信息,交換機(jī)會(huì)將該消息路由到關(guān)心該話題的隊(duì)列中。

3.6 創(chuàng)建消費(fèi)者

接下來(lái),我們就可以定義消息的消費(fèi)者李四、趙五了。他倆分別關(guān)心蘋果采購(gòu)消息和香蕉采購(gòu)消息。也就是監(jiān)聽蘋果消息隊(duì)列和香蕉消息隊(duì)列。

實(shí)例:

/**
 * 消息隊(duì)列接收
 */
@Component
public class RabbitReceiver {
    /**
     * lisi負(fù)責(zé)監(jiān)聽apple-queue
     */
    @RabbitListener(queues = "apple-queue")
    public void lisi(String msg) {
        System.out.println("李四知道:" + msg);
    }

    /**
     * zhaowu負(fù)責(zé)監(jiān)聽banana-queue
     */
    @RabbitListener(queues = "banana-queue")
    public void zhaowu(String msg) {
        System.out.println("趙五知道:" + msg);
    }
}

3.7 測(cè)試

運(yùn)行啟動(dòng)類,從 RabbitMQ 管理界面可以看到已生成指定名稱的隊(duì)列了。

5ed1fba809d1ae1a06350424.jpg

RabbitMQ 已生成隊(duì)列

此時(shí)我們定義一個(gè)控制器用于發(fā)起測(cè)試,直接使用 rabbitTemplate 發(fā)送消息即可。

實(shí)例:

@RestController
public class TestController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/test")
    public void test() {
        // 發(fā)送消息 參數(shù)分別為:交換機(jī)名稱、路由鍵、消息內(nèi)容
        rabbitTemplate.convertAndSend("exchange-topic", "apple", "蘋果來(lái)了10斤");
        rabbitTemplate.convertAndSend("exchange-topic", "banana", "香蕉來(lái)了5斤");
        rabbitTemplate.convertAndSend("exchange-topic", "apple.banana", "蘋果來(lái)了8斤;香蕉來(lái)了20斤");
    }
}

convertAndSend() 方法的第 1 個(gè)參數(shù)表示交換機(jī),第 2 個(gè)參數(shù)表示路由鍵(消息的話題),第 3 個(gè)是消息內(nèi)容。

所以第 1 個(gè)消息會(huì)被 apple-queue 接收,第 2 個(gè)消息會(huì)被 banana-queue 接收,第 3 個(gè)消息會(huì)被兩個(gè)隊(duì)列接收。

我們啟動(dòng)項(xiàng)目,然后訪問(wèn) http://127.0.0.1:8080/test ,控制臺(tái)輸出如下,驗(yàn)證成功。

趙五知道:香蕉來(lái)了5斤
李四知道:蘋果來(lái)了10斤
趙五知道:蘋果來(lái)了8斤;香蕉來(lái)了20斤
李四知道:蘋果來(lái)了8斤;香蕉來(lái)了20斤

4. 小結(jié)

本小節(jié)通過(guò)一個(gè)實(shí)際應(yīng)用場(chǎng)景,演示了 Spring Boot 中使用 RabbitMQ 消息隊(duì)列的方法。

至此, Spring Boot 的內(nèi)容就全部結(jié)束了。紙上得來(lái)終覺淺,絕知此事要躬行。任何的實(shí)用技能都需要在不斷練習(xí)與使用中感悟、完善、提升, Spring Boot 也不例外。

所以還沒(méi)有使用 Spring Boot 的朋友,抓緊上手吧!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容