一、介紹
(一)RabbitMQ
MQ全稱爲Message Queue,即消息隊列, RabbitMQ是由erlang語言開發,基於AMQP(Advanced Message
Queue 高級消息隊列協議)協議實現的消息隊列,它是一種應用程序之間的通信方法,消息隊列在分佈式系統開
發中應用非常廣泛。RabbitMQ官方地址:http://www.rabbitmq.com/
開發中消息隊列通常有如下應用場景:
1、任務異步處理。
將不需要同步處理的並且耗時長的操作由消息隊列通知消息接收方進行異步處理。提高了應用程序的響應時間。
2、應用程序解耦合
MQ相當於一箇中介,生產方通過MQ與消費方交互,它將應用程序進行解耦合。
市場上還有哪些消息隊列?
ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ、Redis。
爲什麼使用RabbitMQ呢?
- 使得簡單,功能強大。
- 基於AMQP協議。
- 社區活躍,文檔完善。
- 高併發性能好,這主要得益於Erlang語言。
- Spring Boot默認已集成RabbitMQ
(二)其他相關知識
AMQP是什麼 ?
AMQP,即Advanced Message Queuing Protocol,一個提供統一消息服務的應用層標準高級消息隊列協議,是應用層協議的一個開放標準,爲面向消息的中間件設計。基於此協議的客戶端與消息中間件可傳遞消息,並不受客戶端/中間件不同產品,不同的開發語言等條件的限制。Erlang中的實現有 RabbitMQ等。
- 總結:AMQP是一套公開的消息隊列協議,最早在2003年被提出,它旨在從協議層定義消息通信數據的標準格式,
爲的就是解決MQ市場上協議不統一的問題。RabbitMQ就是遵循AMQP標準協議開發的MQ服務。
官方:http://www.amqp.org/
JMS是什麼 ?
JMS即Java消息服務(Java Message Service)應用程序接口,是一個Java平臺中關於面向消息中間件(MOM)的API,用於在兩個應用程序之間,或分佈式系統中發送消息,進行異步通信。Java消息服務是一個與具體平臺無關的API,絕大多數MOM提供商都對JMS提供支持。
- JMS是java提供的一套消息服務API標準,其目的是爲所有的java應用程序提供統一的消息通信的標準,類似java的jdbc,只要遵循jms標準的應用程序之間都可以進行消息通信。它和AMQP有什麼 不同,jms是java語言專屬的消息服務標準,它是在api層定義標準,並且只能用於java應用;而AMQP是在協議層定義的標準,是跨語言的。
二、入門初探
(一) RabbitMQ的工作原理
- RabbitMQ的基本結構
組成部分說明如下: - Broker:消息隊列服務進程,此進程包括兩個部分:Exchange和Queue。
- Exchange:消息隊列交換機,按一定的規則將消息路由轉發到某個隊列,對消息進行過慮。
- Queue:消息隊列,存儲消息的隊列,消息到達隊列並轉發給指定的消費方。
- Producer:消息生產者,即生產方客戶端,生產方客戶端將消息發送到MQ。
- Consumer:消息消費者,即消費方客戶端,接收MQ轉發的消息。
消息發佈接收流程:
-----發送消息-----
- 生產者和Broker建立TCP連接。
- 生產者和Broker建立通道。
- 生產者通過通道消息發送給Broker,由Exchange將消息進行轉發。
- Exchange將消息轉發到指定的Queue(隊列)
----接收消息-----
- 消費者和Broker建立TCP連接
- 消費者和Broker建立通道
- 消費者監聽指定的Queue(隊列)
- 當有消息到達Queue時Broker默認將消息推送給消費者。
- 消費者接收到消息。
(二)下載安裝
RabbitMQ由Erlang語言開發,Erlang語言用於併發及分佈式系統的開發,在電信領域應用廣泛,OTP(OpenTelecom Platform)作爲Erlang語言的一部分,包含了很多基於Erlang開發的中間件及工具庫,安裝RabbitMQ需要安裝Erlang/OTP,並保持版本匹配,如下圖:RabbitMQ的下載地址:http://www.rabbitmq.com/download.html
本項目使用Erlang/OTP 20.3版本和RabbitMQ3.7.3版本。
1)下載erlang
地址如下:
http://erlang.org/download/otp_win64_20.3.exe
或去老師提供的軟件包中找到 otp_win64_20.3.exe,以管理員方式運行此文件,安裝。
erlang安裝完成需要配置erlang環境變量: ERLANG_HOME=D:\Program Files\erl9.3 在path中添
加%ERLANG_HOME%\bin;
2)安裝RabbitMQ
https://github.com/rabbitmq/rabbitmq-server/releases/tag/v3.7.3
或去老師提供的軟件包中找到 rabbitmq-server-3.7.3.exe,以管理員方式運行此文件,安裝。
3)啓動
安裝成功後會自動創建RabbitMQ服務並且啓動。
- 從開始菜單啓動RabbitMQ
完成在開始菜單找到RabbitMQ的菜單:
RabbitMQ Service-install :安裝服務
RabbitMQ Service-remove 刪除服務
RabbitMQ Service-start 啓動
RabbitMQ Service-stop 啓動 - 如果沒有開始菜單則進入安裝目錄下sbin目錄手動啓動:
- 安裝並運行服務
rabbitmq-service.bat install 安裝服務 rabbitmq-service.bat stop 停止服務 rabbitmq-service.bat start 啓動服務 - 安裝管理插件
安裝rabbitMQ的管理插件,方便在瀏覽器端管理RabbitMQ
管理員身份運行 rabbitmq-plugins.bat enable rabbitmq_management
-
啓動成功 登錄RabbitMQ進入瀏覽器,輸入:http://localhost:15672
初始賬號和密碼:guest/guest
注意事項
1、安裝erlang和rabbitMQ以管理員身份運行
2、當卸載重新安裝時會出現RabbitMQ服務註冊失敗,此時需要進入註冊表清理erlang搜索RabbitMQ、ErlSrv,將對應的項全部刪除。
3、RabbitMQ Server 安裝後http://localhost:15672/ 無法訪問的解決
打開RabbitMQ Server的開始菜單安裝目錄
選擇RabbitMQ Command Prompt 命令行並打開,輸入
rabbitmq-plugins enable rabbitmq_management
再啓動sever 嘗試訪問,問題解決
二、Hello World
按照官方教程測試Hello World
1、搭建環境
(1)java client
生產者和消費者都屬於客戶端,rabbitMQ的java客戶端如下:
我們先用 rabbitMQ官方提供的java client測試,目的是對RabbitMQ的交互過程有個清晰的認識。
參考 :https://github.com/rabbitmq/rabbitmq-java-client/
(2)創建maven工程
創建生產者工程和消費者工程,分別加入RabbitMQ java client的依賴。
xc-rabbitmq-producer:生產者工程
xc-rabbitmq-consumer:消費者工程
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
</dependencies>
(3)生產者
在生產者工程下的test中創建測試類如下:
package com.xuecheng.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author 麥客子
* @desc rabbitMq入門程序 生產者
* @email [email protected]
* @create 2019/04/22 21:41
**/
public class ProducerTest {
// 隊列名稱
private static final String QUEUE = "helloChina";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
// rabbitmq默認虛擬機名稱爲“/”,虛擬機相當於一個獨立的mq服務器
factory.setVirtualHost("/");
// 創建與RabbitMQ服務的TCP連接
connection = factory.newConnection();
// 創建與Exchange的通道,每個連接可以創建多個通道,每個通道代表一個會話任務
channel = connection.createChannel();
/**
* 聲明隊列,如果Rabbit中沒有此隊列將自動創建
* param1:隊列名稱
* param2:是否持久化
* param3:隊列是否獨佔此連接
* param4:隊列不再使用時是否自動刪除此隊列
* param5:隊列參數
*/
channel.queueDeclare(QUEUE, true, false, false, null);
String message = "helloChina中國" + System.currentTimeMillis();
/**
* 消息發佈方法
* param1:Exchange的名稱,如果沒有指定,則使用Default Exchange
* param2:routingKey,消息的路由Key,是用於Exchange(交換機)將消息轉發到指定的消息隊列
* param3:消息包含的屬性
* param4:消息體
*/
/**
* 這裏沒有指定交換機,消息將發送給默認交換機,每個隊列也會綁定那個默認的交換機,但是不能顯
示綁定或解除綁定
* 默認的交換機,routingKey等於隊列名稱
*/
channel.basicPublish("", QUEUE, null, message.getBytes());
System.out.println("Send Message is:'" + message + "'");
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
}
}
}
(4)消費者
在消費者工程下的test中創建測試類如下:
package com.xuecheng.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @author 麥客子
* @desc rabbitMq入門程序 消費者
* @email [email protected]
* @create 2019/04/22 22:04
**/
public class ConsumerTest {
private static final String QUEUE = "helloChina";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
// 設置RabbitMQ所在服務器的ip和端口
factory.setHost("127.0.0.1");
factory.setPort(5672);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 聲明隊列
channel.queueDeclare(QUEUE, true, false, false, null);
// 定義消費方法
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
* 消費者接收消息調用此方法
* @param consumerTag 消費者的標籤,在channel.basicConsume()去指定
* @param envelope 消息包的內容,可從中獲取消息id,消息routingkey,交換機,消息和重傳標誌
(收到消息失敗後是否需要重新發送)
* @param properties
* @param body
* @throws IOException
}*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
// 交換機
String exchange = envelope.getExchange();
// 路由key
String routingKey = envelope.getRoutingKey();
// 消息id
long deliveryTag = envelope.getDeliveryTag();
// 消息內容
String msg = new String(body, "utf-8");
System.out.println("receive message.." + msg);
}
};
/**
* 監聽隊列String queue, boolean autoAck,Consumer callback
* 參數明細
* 1、隊列名稱
* 2、是否自動回覆,設置爲true爲表示消息接收到自動向mq回覆接收到了,mq接收到回覆會刪除消息,設置
爲false則需要手動回覆
* 3、消費消息的方法,消費者接收到消息後調用此方法
*/
channel.basicConsume(QUEUE, true, consumer);
}
}
(5)總結
1、發送端操作流程
1)創建連接
2)創建通道
3)聲明隊列
4)發送消息
2、接收端
1)創建連接
2)創建通道
3)聲明隊列
4)監聽隊列
5)接收消息
6)ack回覆