Spring Boot(十):整合RabbitMQ消息中間件

RabbitMQ背景

消息隊列中間件是分佈式系統中重要的組件,主要解決應用耦合,異步消息,流量削鋒等問題。實現高性能,高可用,可伸縮和最終一致性。

消息中間件的分類

①、ActiveMQ:是Apache軟件基金會所研發的開放源代碼消息中間件;由於ActiveMQ是一個純Java程序,因此只需要操作系統支持Java虛擬機,ActiveMQ便可執行。
②、RabbitMQ:是實現了高級消息隊列協議(AMQP)的開源消息代理軟件(亦稱面向消息的中間件)。RabbitMQ服務器是用Erlang語言編寫的,而集羣和故障轉移是構建在開放電信平臺框架上的。所有主要的編程語言均有與代理接口通訊的客戶端庫。
③、Kafka:是由Apache軟件基金會開發的一個開源流處理平臺,由Scala和Java編寫。Kafka是一種高吞吐量的分佈式發佈訂閱消息系統,它可以處理消費者在網站中的所有動作流數據。
④、RocketMQ:是阿里巴巴集團自主研發的專業消息中間件。

上面每個消息中間件的解釋大部分來自百度百科。

RabbitMQ的特點

1、可靠性:使用一些機制來保證可靠性,如持久化、傳輸確認、發佈確認。
2、消息集羣:多個RabbitMQ服務器可以組成一個集羣,形成一個邏輯Broker(緩存代理)。
3、高可用:隊列可以在集羣中的機器上進行鏡像,使得在部分節點出問題的情況下隊列仍然可用。
4、多種協議:RabbitMQ支持多種消息隊列協議,比如STOMP、MQTT等。
5、多語言客戶端:RabbitMQ幾乎支持所有常用語言,比如Java、.NET、Ruby等。
6、管理界面:RabbitMQ提供了一個易用的用戶界面,使得用戶可以監控和管理消息Broker的許多方面。
7、插件機制:RabbitMQ提供了許多插件,來從多方面進行擴展,也可以編寫自己的插件。
8、跟蹤機制:如果消息異常,RabbitMQ提供了消息跟蹤機制。

RabbitMQ架構圖的介紹

圖片引用於百度
ps: 圖片來源於網絡

根據這張架構圖,可以對RabbitMQ中各個組件進行介紹:

RabbitMQ Server:也叫Broker Server,它是一種傳輸服務。 它的角色就是維護一條從Producer到Consumer的路線,保證數據能夠按照指定的方式進行傳輸。

Producer:消息生產者,消息生產者連接RabbitMQ服務器然後將消息投遞到Exchange。

Consumer:消息消費者,消息消費者訂閱隊列,RabbitMQ將Queue中的消息發送到消息消費者。

Exchange:生產者將消息發送到Exchange(交換器),由Exchange將消息路由到一個或多個Queue中(或者丟棄)。Exchange並不存儲消息。RabbitMQ中的Exchange有direct、fanout、topic、headers四種類型,每種類型對應不同的路由規則。

Queue:(隊列)是RabbitMQ的內部對象,用於存儲消息。消息消費者就是通過訂閱隊列來獲取消息的,RabbitMQ中的消息都只能存儲在Queue中,生產者生產消息並最終投遞到Queue中,消費者可以從Queue中獲取消息並消費。多個消費者可以訂閱同一個Queue,這時Queue中的消息會被平均分攤給多個消費者進行處理,而不是每個消費者都收到所有的消息並處理。

RoutingKey:生產者在將消息發送給Exchange的時候,一般會指定一個Routing key,來指定這個消息的路由規則,而這個Routing key需要與Exchange Type及Binding key聯合使用才能最終生效。在Exchange Type與Binding key固定的情況下(在正常使用時一般這些內容都是固定配置好的),我們的生產者就可以在發送消息給Exchange時,通過指定Routing key來決定消息流向哪裏。RabbitMQ爲Routing key設定的長度限制爲255bytes。

Connection:(連接):Producer和Consumer都是通過TCP連接到RabbitMQ Server的。程序的起始處就是建立這個TCP連接。

Channels:(信道):它建立在上述的TCP連接中。數據流動都是在Channel中進行的。也就是說,一般情況是程序起始建立TCP連接,第二步就是建立這個Channel。

VirtualHost:權限控制的基本單位,一個VirtualHost裏面有若干Exchange和MessageQueue,以及指定被哪些user使用。

RabbitMQ的安裝

至於RabbitMQ的安裝,這裏就不做說明了,網上也有很多安裝教程,各位讀者可以根據相關資料進行安裝。博主這裏使用的是本地Windows上安裝的RabbitMQ。安裝完成,通過命令安裝管理界面:

rabbitmq‐plugins enable rabbitmq_management

然後輸入地址:http://127.0.0.1:15672,就能看到如下界面。

用戶名和密碼默認爲: guest

三種模式的講解與代碼實現

RabbitMQ有三種模式:直接模式(Direct)、分列模式(Fanout)、主題模式(Topic)。

直接模式(Direct)

將消息發給唯一一個節點時使用這種模式。任何發送到Direct Exchange的消息都會被轉發到RouteKey中指定的Queue。

特點
1、可以使用RabbitMQ自帶的Exchange " " (該Exchange的名字爲空字符串);
2、這種模式下不需要將Exchange進行任何綁定操作;
3、消息傳遞時需要一個"RouteKey",可以理解爲要發送到的隊列名;
4、如果vhost中不存在RouteKey中指定的隊列名,則該消息會被拋棄。

代碼實現
這裏使用的是SpringBoot,需要引入RabbitMQ的pom依賴。

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

然後增加RabbitMQ的配置。

spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest

配置完成,先創建消息的生產者,這裏使用SpringBoot中提供的測試類。

@RunWith(SpringRunner.class)
@SpringBootTest
public class MonitorApplicationTests {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void direct(){
        rabbitTemplate.convertAndSend("qfcwx","direct模式");
    }
}

注意,這裏一定要先通過RabbitMQ的管控臺創建好名爲"qfcwx"的隊列。不然啓動會報錯的。

然後啓動測試類,再通過管控臺查看當前消息隊列中是否存在消息。

可以看到,此時隊列中確實是有一條消息等待消費。

然後創建消息的消費者。

@Component
@RabbitListener(queues = "qfcwx")
public class DirectListener {

    @RabbitHandler
    private void direct(String message){
        System.out.println("direct模式下收到的消息:" + message);
    }
}

@RabbitListener:標註在類上面的時候,需要配合@RabbitHandler註解一起使用,queues指明監聽哪個隊列。

運行啓動類,通過控制檯看輸出結果。

查看管控臺發現,隊列中的消息也被消費了。

分列模式(Fanout)

將消息一次發給多個隊列時,需要使用這種模式。任何發送到Fanout Exchange的消息都會被轉發到與該Exchange綁定的所有Queue上。

特點
1、這種模式不需要RouteKey。
2、這種模式需要提前將Exchange與Queue進行綁定,一個Exchange可以綁定多個Queue,一個Queue可以同多個Exchange進行綁定。
3、如果接受到消息的Exchange沒有與任何Queue綁定,則消息會被丟棄。

代碼實現
這次首先通過管控臺創建Exchange與Queue。這裏創建名爲"qfcwx_exchange"的交換器,然後創建名爲"qfcwx_a"、"qfcwx_b"的兩個隊列。然後將兩個隊列綁定到交換器上。

接着通過代碼編寫生產者:

    @Test
    public void fanout(){
        rabbitTemplate.convertAndSend("qfcwx_exchange","","fanout模式");
    }

然後創建消費者:

@Component
public class FanoutListener {

    @RabbitListener(queues = "qfcwx_a")
    public void fanoutToQueueOne(String message) {
        System.out.println("隊列[qfcwx_a],收到了交換機[qfcwx_exchange]的消息:" + message);
    }

    @RabbitListener(queues = "qfcwx_b")
    public void fanoutToQueueTwo(String message) {
        System.out.println("隊列[qfcwx_b],收到了交換機[qfcwx_exchange]的消息:" + message);
    }
}

直接啓動測試類,通過控制檯查看結果。

主題模式(Topic)

任何發送到Topic Exchange的消息都會被轉發到所有關心RouteKey中指定話題的Queue上,交換器是一個名稱與隊列綁定的列表。當消息發佈到交換器時,實際上是由你所連接的信道,將消息路由鍵同交換器上綁定的列表進行比較,最後路由消息。

看到這裏,相信很多讀者會一臉懵逼,下面用表格展示一下。

routing key binding key
qfcwx.mobile qfcwx.#
test.mail test.#

表格只是大致說明這是一種匹配的規則。符號 # 匹配一個或多個詞,符號 * 匹配不多不少一個詞。這裏也許博主說的比較模糊了。等會通過代碼來講解吧。

特點
1、每個隊列都有其關心的主題,所有的消息都帶有一個"標題"(RouteKey),Exchange會將消息轉發到所有關注主題能與RouteKey模糊匹配的隊列。
2、這種模式需要RouteKey,也需要綁定Exchange與Queue。
3、在進行綁定時,要提供一個該隊列關心的主題,如"#.log.#“表示該隊列關心所有涉及log的消息。
4、”#“表示0個或若干個關鍵字,”"表示一個關鍵字。如"log."能與"log.warn"匹配,無法與"log.warn.timeout"匹配;但是"log.#"能與上述兩者匹配。
5、如果Exchange沒有發現能夠與RouteKey匹配的Queue,則會拋棄此消息。

代碼實現

還是先操作管控臺,創建一個交換機,命名爲log_exchange。

然後,分別創建交互機下隊列與routing的匹配規則。


接着創建生產者:

    @Test
    public void topic() {
        rabbitTemplate.convertAndSend("log_exchange", "log.error", "topic模式");
        rabbitTemplate.convertAndSend("log_exchange", "debug.log", "topic模式");
        rabbitTemplate.convertAndSend("log_exchange", "info.log", "topic模式");
    }

這裏指定了交換機的名稱和routingkey。

創建消費者。

@Component
public class TopicListener {

    @RabbitListener(queues = "qfcwx_a")
    public void topicToQueueOne(String message) {
        System.out.println("隊列[qfcwx_a],收到了交換機[log_exchange]的消息:" + message);
    }

    @RabbitListener(queues = "qfcwx_b")
    public void topicToQueueTwo(String message) {
        System.out.println("隊列[qfcwx_b],收到了交換機[log_exchange]的消息:" + message);
    }

    @RabbitListener(queues = "qfcwx_c")
    public void topicToQueueThree(String message) {
        System.out.println("隊列[qfcwx_c],收到了交換機[log_exchange]的消息:" + message);
    }
}

啓動程序,看控制太打印的結果。

因爲上面生產者的routingkey與我們先前在管控臺配置的"qfcwx_c"隊列的routingkey不匹配,所以,隊列"qfcwx_c"並沒有收到消息。這就是主題模式的使用方法。

到這裏,關於RabbitMQ與SpringBoot整合的內容就講完了。全文其實大部分都在講解RabbitMQ的知識,特別是三種模式,一、二種模式好理解,第三種還需要結合代碼來理解。如果文中存在什麼問題或者錯誤的地方,也希望各位讀者提出。

人都有以第一印象定好壞的習慣,以爲一個人好時,就會愛屋及烏,以爲一個人不好時,就會全盤否認。

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