使用Spring AMQP進行消息傳遞
本文討論使用Spring AMQP框架實現AMQP消息通信。先介紹一些消息通信核心概念,然後通過一個實際示例進行實戰。
1. 核心概念
1.1. 消息傳輸
消息傳輸是應用間進行消息通信的技術,基於異步消息傳輸代替基於請求-響應的同步架構。消息的生產者和消費者被中介消息層(也稱爲消息代理)解耦。消息代理具有消息持久化、消息過濾以及消息轉換等特性。
消息傳遞鍵間的應用都是Java語言實現,則通常使用 JMS (Java Message Service) API。對於不同平臺和提供商之間相互通信不能使用JMS客戶端和代理服務器,這時需要使用AMQP。
1.2. AMQP – Advanced Message Queuing Protocol
AMQP是實現異步消息通信的開放標準連接規範,提供了應該如何構造消息的描述。
與JMS的差異
AMQP是平臺獨立二進制協議標準,庫可以使用不同語言實現並運行與不同環境中。不受限與特定廠商,因此可以實現JMS代理之間遷移,主流的AMQP消息代理是 RabbitMQ, OpenAMQ, StormMQ。
AMQP實體
簡要理解,AMQP有Exchange, Queue, Binding組成:
Exchange類似於郵電局或郵箱,客戶端發佈消息至AMQP exchange,有四種內置交換類型:
直接交換(Direct Exchange):通過完全匹配路由key路由消息至特定的隊列。
扇出交換(Fanout Exchange): 路由消息至所有綁定的隊列。
主題交換(Topic Exchange):路由消息至匹配特定模式的路由key的多個隊列。
頭信息交換(Headers Exchange): 基於消息頭路由消息。
Queue 使用路由key綁定exchange。
Message 消息使用路由key發送至exchange,然後exchange分發消息副本至各個隊列。
Spring AMQP
Spring AMQP有兩個模塊組成:spring-amqp 和 spring-rabbit,這些模塊提供下列內容的抽象:
AMQP 實體 – 使用Message, Queue, Binding, Exchange 類創建AMQP 實體。
連接管理 – 使用CachingConnectionFactory連接至 RabbitMQ 代理。
消息發佈 – 使用RabbitTemplate發送消息。
消息消費 – 使用 @RabbitListener 註解從隊列讀消息。
2. 創建Spring Amqp 示例應用
2.1. 安裝 AMQP 消息代理
首先需要連接到RabbitMQ消息代理服務,最簡單的方法是使用Docker獲取並運行RabbitMQ:
docker run -d -p 5672:5672 -p 15672:15672 --name my-rabbit rabbitmq:3-management
我們暴露5672端口爲了讓我們應用可以連接RabbitMQ。同時暴露15672爲了通過管理界面看RabbitMQ正在做什麼,url爲:http://localhost:15672 ,HTTP API: http://localhost:15672/api/index.html。
現在我們通過Spring AMQP創建應用發送和接收"hello world"消息.
2.2. MAVEN依賴
爲了增加spring-amqp 和 spring-rabbit 模塊,需增加boot-starter-amqp 依賴:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
</dependencies>
讀者可以適合的版本。
2.3. 連接至RabbitMQ代理服務器
使用Spring Boot 自動配置創建了 ConnectionFactory, RabbitTemplate, RabbitAdmin bean。因此我們有至RabbitMQ的連接在5672,並使用缺省的用戶和密碼:guest。我們僅需要災厄應用使用 @SpringBootApplication註解:
@SpringBootApplication
public class HelloWorldMessageApp {
// ...
}
2.4. 創建隊列
通過簡單定義Queue類型bean即可創建隊列。RabbitAdmin會發現並使用路由key(myQueue)綁定至缺省exchange:
@Bean
public Queue myQueue() {
return new Queue("myQueue", false);
}
如果需要定義多個隊列,使用不同的方法名,則默認Bean名稱與方法名一致。
@Bean
Queue queue1() {
return new Queue(“queue1”, false);
}
@Bean
Queue queue2() {
return new Queue(“queue2”, false);
}
我們將隊列設置爲非持久性,即當RabbitMQ停止時隊列中的任何消息將會刪除。但重啓我們應用程序對隊列沒有影響。
如果需要重啓消息代理服務器隊列仍然存在,需要通過參數true設置隊列爲持久狀態,但不能保證其中的消息仍然存在,如果必要需設置消息投遞模式爲持久化模式。
2.5. 發送消息
使用RabbitTemplate 發送 “Hello, world!”:
rabbitTemplate.convertAndSend("myQueue", "Hello, world!");
2.6. 消費消息
通過@RabbitListener註解實現消費消息:
@RabbitListener(queues = "myQueue")
public void listen(String in) {
System.out.println("Message read from myQueue : " + in);
}
2.7. 運行示例
首先啓動RabbitMQ代理:
docker run -d -p 5672:5672 -p 15672:15672 --name my-rabbit rabbitmq:3-management
然後運行spring boot應用,HelloWorldMessage.java中的main方法:
mvn spring-boot:run -Dstart-class=com.baeldung.springamqp.simple.HelloWorldMessageApp
當應用正運行時我們會看到:
- 應用發送消息至缺省exchange,使用myQueue作爲路由key
- 然後隊列myQueue接收到消息
- 最後監聽方法從隊列myQueue中消費消息,然後打印至控制檯
我們也可以使用RabbitMQ管理url http://localhost:15672 查看發送的消息和消費的消息。
3. 總結
本文我們介紹使用Spring AMQP實現AMQP規範的消息通信應用。