引言
RabbitMQ是基於AMQP協議(具有天然的跨平臺性),有erlang語言開發,是目前部署最廣泛的開源消息中間件,它的優勢在於erlang語言開發,適用於socket開發,其次是它天生與spring框架整合非常方便,最後它在處理消息的丟失,事務一致性方便處理的十分嚴密,幾乎沒有丟失。
生產者產生消息後,放在exchange中,exchange將消息一個一個的放在消息隊列中,消費者與消息隊列進行綁定,從而獲取消息
目錄
一:rabbitMQ的安裝
1. 官網:https://www.rabbitmq.com/
下載不止要下載rabbit的安裝包,還要下載erlang語言的支持,因爲rabbitMQ是基於該語言開發的。而且erlang的版本要與rabbit的版本兼容
有三個:erlang-22.0.7-1.el7.x86_64.rpm、rabbitmq-server-3.7.18.rpm、socat-1.7.3.2.rpm
安裝教程參考博客:https://blog.csdn.net/qq_20492999/article/details/81254242
2. 登錄到rabbit的web管理界面,可進行添加賬號,虛擬主機綁定,通道管理,交換機管理等操作
二:rabbitMQ的使用
<一>:直連模式
生產者發送消息(通過通道將消息放在隊列)、消費者一直等待消息的到來
1. 發佈消息
public void test1() throws Exception{
//創建MQ連接工廠
ConnectionFactory connectionFactory = new ConnectionFactory();
//設置連接rabbitmq主機
connectionFactory.setHost("127.0.0.1");
//設置連接端口號
connectionFactory.setPort(5672);
//設置連接的虛擬主機
connectionFactory.setVirtualHost("/admin");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
//獲取連接對象
Connection connection = connectionFactory.newConnection();
//獲取連接中通道對象
Channel channel = connection.createChannel();
/*
通道綁定 對應消息隊列
p1: 隊列名稱,如果不存在會自動創建
p2: 是否持久化,即rabbitmq重啓後,該隊列是否還存在,true時,該隊列對存放在磁盤。false時,重啓後不復存在,僅僅是隊列的持久化,不管是true還是false隊列中的消息都會丟失,需要在發佈消息的時候進行持久化
p3: 是否獨佔隊列,代表此隊列是否只能被當前連接所使用。true:其他連接不可使用
p4: 是否在消費完成後,自動刪除隊列,true:刪除,false:不刪除
p5: 額外附加參數
*/
channel.queueDeclare("hello",false,false,false,null);
// 此時與MQ的連接已經完成,通道已經創建,通道與隊列已經完成綁定。
// 可以進行發佈消息了
/*
p1: 交換機名稱
p2: 隊列名稱
p3: 傳遞消息額外設置,可以通過參數,將消息設置爲持久化MessageProperties.PERSISTENT_TEXT_PLAIN,當隊列與消息均爲持久化時,消息就不會被丟失
p4: 消息的具體內容
*/
channel.basicPublish("","hello",MessageProperties.PERSISTENT_TEXT_PLAIN,"hello rabbitmq".getBytes());
channel.close();
connection.close();
}
2. 消費消息
public static void main(String[] args) throws Exception{
//創建MQ連接工廠
ConnectionFactory connectionFactory = new ConnectionFactory();
//設置連接rabbitmq主機
connectionFactory.setHost("127.0.0.1");
//設置連接端口號
connectionFactory.setPort(5672);
//設置連接的虛擬主機
connectionFactory.setVirtualHost("/admin");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
Connection connection = connectionFactory.newConnection();
//創建通道對象
Channel channel = connection.createChannel();
//通道綁定隊列,消費者對同一個隊列的定義,需要與消費者對該隊列的定義一致,不要出現,消費者定義該隊列爲持久化,
//生產者定義的是不持久化,否則會出現問題
channel.queueDeclare("hello", false, false, false, null);
//消費消息
//方法一:
/*
p1: 消費消息隊列的名稱
p2: 開啓消息的自動確認機制
p3: 消費時的回調接口
*/
/*channel.basicConsume("hello",true,new DefaultConsumer(channel) {
@Override //body參數,就是我們拿到的消息
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("message is " + new String(body));
}
});*/
//方法二:rabbitMQ官網給出的example:
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody());
System.out.println("message is that:" + message);
};
channel.basicConsume("hello", true, deliverCallback, consumerTag -> {});
//如果通道關閉或者連接關閉,就會導致我們的消費者還沒來得及消費消息,或者還沒有消費完,通道連接就關閉了,
//從而導致消息沒有被正確處理
/*channel.close();
connection.close();*/
}
3. 特性:這種方式是最簡單的點對點的消息隊列模型,《一個通道只能被一個消費者使用》。
儘管簡單,但是使用可以根據業務邏輯變得廣泛
4. 對於實際的項目中,可以將MQ的連接信息封裝在配置文件中,通過啓動bean的方式將MQ的連接工廠進行註冊,後續使用時可通過注入的方式使用連接工廠獲取通道
一個通道(channel)可以向多個隊列(queue)發送消息
<二>. Work模型(工作隊列work Queue)
簡介:當消息處理比較耗時時,可能存在生產者生產消息的速度遠遠大於消息的速度,從而導致消息在隊列中的堆積,得不到即時消費,影響業務。此時就可以使用work模型,多個消費者綁定到同一個隊列,共同消費隊列中的消息,隊列中的消息一旦被消費就會消息所以不會重複處理消息的。
1. 創建消息生產者(參考上面代碼)
2. 創建兩個一樣的消費者,綁定同一個隊列(參考上面代碼)
總結:默認情況下,rabbitMQ將按順序將每個消息發送給下一個消費者,也就是說,在work模型中,不管有多少個消費者,他們處理的消息都是一樣的。