1.概述。
- 大多應用中,可通過消息服務中間件來提升系統異步通信、擴展解耦能力。
- 消息服務中兩個重要概念: 消息代理(message broker)和目的地(destination)。 當消息發送者發送消息以後,將由消息代理接管,消息代理保證消息傳遞到指定目的地。
- 消息隊列主要有兩種形式的目的地 :
- 隊列(queue):點對點消息通信(point-to-point)
- 主題(topic):發佈(publish)/訂閱(subscribe)消息通信
- 點對點式: 消息發送者發送消息,消息代理將其放入一個隊列中,消息接收者從隊列中獲取消息內容,消息讀取後被移出隊列 消息只有唯一的發送者和接受者,但並不是說只能有一個接收者
- 發佈訂閱式: 發送者(發佈者)發送消息到主題,多個接收者(訂閱者)監聽(訂閱)這個主題,那麼就會在消息到達時同時收到消息
- JMS(Java Message Service)JAVA消息服務: 基於JVM消息代理的規範。ActiveMQ、HornetMQ是JMS實現
- AMQP(Advanced Message Queuing Protocol): 高級消息隊列協議,也是一個消息代理的規範,兼容JMS RabbitMQ是AMQP的實現
- Spring支持
- spring-jms提供了對JMS的支持
- spring-rabbit提供了對AMQP的支持
- 需要ConnectionFactory的實現來連接消息代理
- 提供JmsTemplate、RabbitTemplate來發送消息
- @JmsListener(JMS)、@RabbitListener(AMQP)註解在方法上監聽消息代理髮布的消息
- @EnableJms、@EnableRabbit開啓支持
- Spring Boot自動配置
- JmsAutoConfiguration
- RabbitAutoConfiguration
2.應用場景 。
- 異步處理
- 第一種情況屬於同步處理。用戶發起註冊請求,服務器將數據寫入到數據庫用50ms,再發送郵件用50ms,再發送短信用50ms,這樣用戶等待時間就是150ms。
- 第二種情況屬於併發操作。用戶發起註冊請求,服務器將數據寫入到數據庫用50ms,再用多線程的方式同時執行發送郵件和發送短信使用50ms,這樣用戶等待時間就是100ms。
- 第三種情況屬於消息處理。用戶發送註冊請求,服務器將數據寫入到數據庫用了50ms,將註冊的信息寫入到消息隊列用了5ms左右,然後就可以響應給用戶已經註冊成功。後面的操作就是,監聽消息隊列(如果隊列有消息),獲取註冊的信息,發送郵件和發送短信給用戶即可。
3.RabbitMQ簡介
- RabbitMQ簡介:
- RabbitMQ是一個由erlang開發的AMQP(Advanved Message Queue Protocol)的開源實現。
- 核心概念
- Message
- 消息,消息是不具名的,它由消息頭和消息體組成。消息體是不透明的,而消息頭則由一系列的可選屬性組成,這些屬性包括routing-key(路由鍵)、priority(相對於其他消息的優先權)、delivery-mode(指出該消息可能需要持久性存儲)等。
- Publisher
- 消息的生產者,也是一個向交換器發佈消息的客戶端應用程序。
- Exchange
- 交換器,用來接收生產者發送的消息並將這些消息路由給服務器中的隊列。
- Exchange有4種類型:
- direct(默認,點對點),fanout(發佈訂閱模式), topic(匹配路由鍵routing key的發佈訂閱模式), 和headers(匹配 AMQP 消息的 header,和direct差不多,但是性能很差,幾乎不用了),不同類型的Exchange轉發消息的策略有所區別。
- Queue
- 消息隊列,用來保存消息直到發送給消費者。它是消息的容器,也是消息的終點。一個消息可投入一個或多個隊列。消息一直在隊列裏面,等待消費者連接到這個隊列將其取走。
- Binding
- 綁定,用於消息隊列和交換器之間的關聯。一個綁定就是基於路由鍵將交換器和消息隊列連接起來的路由規則,所以可以將交換器理解成一個由綁定構成的路由表。 Exchange 和Queue的綁定可以是多對多的關係。
- Connection
- 網絡連接,比如一個TCP連接。
- Channel
- 信道,多路複用連接中的一條獨立的雙向數據流通道。信道是建立在真實的TCP連接內的虛擬連接,AMQP 命令都是通過信道發出去的,不管是發佈消息、訂閱隊列還是接收消息,這些動作都是通過信道完成。因爲對於操作系統來說建立和銷燬 TCP 都是非常昂貴的開銷,所以引入了信道的概念,以複用一條 TCP 連接。
- Consumer
- 消息的消費者,表示一個從消息隊列中取得消息的客戶端應用程序。
- Virtual Host
- 虛擬主機,表示一批交換器、消息隊列和相關對象。虛擬主機是共享相同的身份認證和加密環境的獨立服務器域。每個 vhost 本質上就是一個 mini 版的 RabbitMQ 服務器,擁有自己的隊列、交換器、綁定和權限機制。vhost 是 AMQP 概念的基礎,必須在連接時指定,RabbitMQ 默認的 vhost 是 / 。
- Broker
- 表示消息隊列服務器實體
- Message
4.RabbitMQ整合
- 引入 spring-boot-starter-amqp
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency
- application.yml配置
spring.rabbitmq.host=localhost spring.rabbitmq.username=guest spring.rabbitmq.password=guest spring.rabbitmq.port=5672 #spring.rabbitmq.virtual-host=
- 測試RabbitMQ
- AmqpAdmin:管理組件
- RabbitTemplate:消息發送處理組件
@Autowired RabbitTemplate rabbitTemplate; @Autowired AmqpAdmin amqpAdmin; @Test public void createExchange(){ //創建Exchange(direct:點對點模式) //amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange")); //創建Queue隊列,並指定routing-key路由鍵和Durable是否持久化 //amqpAdmin.declareQueue(new Queue("amqpadmin.queue", true)); //創建綁定規則 //amqpAdmin.declareBinding(new Binding("amqpadmin.queue",Binding.DestinationType.QUEUE,"amqpadmin.exchange","amqp.haha",null)); } /** * 1、單播(點對點) */ @Test public void contextLoads() { //Message需要自己構造一個;定義消息體內容和消息頭 //rabbitTemplate.send(exchage, routeKey, message); //object默認當成消息體,只需要傳入要發送的對象,自動序列化發送給rabbitmq; //rabbitTemplate.convertAndSend(exchage, routeKey, object); Map<String,Object> map = new HashMap<>(); map.put("msg","這是第一個消息"); map.put("data", Arrays.asList("helloworld",123,true)); //對象被默認序列化以後發送出去 rabbitTemplate.convertAndSend("exchange.direct", "llsydn.news", map); } //接受數據,如何將數據自動的轉爲json發送出去 @Test public void receive(){ Object o = rabbitTemplate.receiveAndConvert("llsydn.news"); System.out.println(o.getClass()); System.out.println(o); } /** * 廣播 */ @Test public void sendMsg(){ Map<String,Object> map = new HashMap<>(); map.put("msg", "這是第一個消息"); map.put("data", Arrays.asList("helloworld", 123, true)); rabbitTemplate.convertAndSend("exchange.fanout", "", map); }