一、RabbitMQ的工作原理
這裏給大家提供一個配套rabbitmq3.7.3和erlang20.3下載包(外網下載實在是慢啊):rabbitmq和erlang下載
下圖是RabbitMQ的基本結構:
組成部分說明如下:
- Broker:消息隊列服務進程,此進程包括兩個部分:Exchange和Queue。
- Exchange:消息隊列交換機,按一定的規則將消息路由轉發到某個隊列,對消息進行過慮。
- Queue:消息隊列,存儲消息的隊列,消息到達隊列並轉發給指定的消費方。
- Producer:消息生產者,即生產方客戶端,生產方客戶端將消息發送到MQ。
- Consumer:消息消費者,即消費方客戶端,接收MQ轉發的消息。
消息發佈接收流程:
-----發送消息-----
- 生產者和Broker建立TCP連接。
- 生產者和Broker建立通道。
- 生產者通過通道消息發送給Broker,由Exchange將消息進行轉發。
- Exchange將消息轉發到指定的Queue(隊列)
----接收消息-----
- 消費者和Broker建立TCP連接
- 消費者和Broker建立通道
- 消費者監聽指定的Queue(隊列)
- 當有消息到達Queue時Broker默認將消息推送給消費者。
- 消費者接收到消息。
二、rabbitmq入門程序
入門程序只是簡單的生產者發送消息,消費者接收消息!
如果是maven工程需要引入依賴
<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>
生產者測試代碼
public class Producer01 {
private static final String QUEUE = "helloworld";
public static void main(String[] args) {
//隊列
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672); // 端口號
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
// 設置虛擬機, 一個mq服務可以設置多個虛擬機,每個虛擬機就相當於一個獨立的mq
connectionFactory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try {
// 建立連接
connection = connectionFactory.newConnection();
// 創建會話通道,生產者和mq服務所有通信都在channel通道中完成
channel = connection.createChannel();
//聲明隊列,如果隊列在mq 中沒有則要創建
//參數:String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
/**
* 參數明細
* 1、queue 隊列名稱
* 2、durable 是否持久化,如果持久化,mq重啓後隊列還在
* 3、exclusive 是否獨佔連接,隊列只允許在該連接中訪問,如果connection連接關閉隊列則自動刪除,如果將此參數設置true可用於臨時隊列的創建
* 4、autoDelete 自動刪除,隊列不再使用時是否自動刪除此隊列,如果將此參數和exclusive參數設置爲true就可以實現臨時隊列(隊列不用了就自動刪除)
* 5、arguments 參數,可以設置一個隊列的擴展參數,比如:可設置存活時間
*/
channel.queueDeclare(QUEUE, true, false, false, null);
/**
* 參數明細:
* 1、exchange,交換機,如果不指定將使用mq的默認交換機(設置爲"")
* 2、routingKey,路由key,交換機根據路由key來將消息轉發到指定的隊列,如果使用默認交換機,routingKey設置爲隊列的名稱
* 3、props,消息的屬性
* 4、body,消息內容
*/
//消息內容
String message = "Test send Mq queue first!";
channel.basicPublish("",QUEUE,null,message.getBytes());
System.out.println("send to mq "+message);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}finally {
//關閉連接
//先關閉通道
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
結果:
消費者測試代碼
public class Consumer01 {
private static final String QUEUE = "helloworld";
public static void main(String[] args) throws IOException, TimeoutException {
//通過連接工廠創建新的連接和mq建立連接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//設置虛擬機,一個mq服務可以設置多個虛擬機,每個虛擬機就相當於一個獨立的mq
connectionFactory.setVirtualHost("/");
//建立新連接
Connection connection = connectionFactory.newConnection();
//創建會話通道,生產者和mq服務所有通信都在channel通道中完成
Channel channel = connection.createChannel();
//監聽隊列
//聲明隊列,如果隊列在mq 中沒有則要創建
//參數:String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
/**
* 參數明細
* 1、queue 隊列名稱
* 2、durable 是否持久化,如果持久化,mq重啓後隊列還在
* 3、exclusive 是否獨佔連接,隊列只允許在該連接中訪問,如果connection連接關閉隊列則自動刪除,如果將此參數設置true可用於臨時隊列的創建
* 4、autoDelete 自動刪除,隊列不再使用時是否自動刪除此隊列,如果將此參數和exclusive參數設置爲true就可以實現臨時隊列(隊列不用了就自動刪除)
* 5、arguments 參數,可以設置一個隊列的擴展參數,比如:可設置存活時間
*/
channel.queueDeclare(QUEUE, true, false, false, null);
//實現消費方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* 當接收到消息後此方法將被調用
* @param consumerTag 消費者標籤,用來標識消費者的,在監聽隊列時設置channel.basicConsume
* @param envelope 信封,通過envelope
* @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();
//消息id,mq在channel中用來標識消息的id,可用於確認消息已接收
long deliveryTag = envelope.getDeliveryTag();
//消息內容
String message = new String(body, "utf-8");
System.out.println("receive message:" + message);
}
};
//監聽隊列
//參數:String queue, boolean autoAck, Consumer callback
/**
* 參數明細:
* 1、queue 隊列名稱
* 2、autoAck 自動回覆,當消費者接收到消息後要告訴mq消息已接收,如果將此參數設置爲tru表示會自動回覆mq,如果設置爲false要通過編程實現回覆
* 3、callback,消費方法,當消費者接收到消息要執行的方法
*/
channel.basicConsume(QUEUE, true, defaultConsumer);
}
}
結果:
注:有兩條消息是因爲我再次重啓了生產者 消費則這邊因爲隊列還未斷開,所以會繼續接收。