概念認識
Broker:簡單來說就是消息隊列服務器實體。
- Exchange:消息交換機,它指定消息按什麼規則,路由到哪個隊列。
- Queue:消息隊列載體,每個消息都會被投入到一個或多個隊列。
- Binding:綁定,它的作用就是把exchange和queue按照路由規則綁定起來。
- Routing Key:路由關鍵字,exchange根據這個關鍵字進行消息投遞。
- vhost:虛擬主機,一個broker裏可以開設多個vhost,用作不同用戶的權限分離。
- producer:消息生產者,就是投遞消息的程序。
- consumer:消息消費者,就是接受消息的程序。
- channel:消息通道,在客戶端的每個連接裏,可建立多個channel,每個channel代表一個會話任務。
消息隊列的使用過程大概如下:
- 客戶端連接到消息隊列服務器,打開一個channel。
- 客戶端聲明一個exchange,並設置相關屬性。
- 客戶端聲明一個queue,並設置相關屬性。
- 客戶端使用routing key,在exchange和queue之間建立好綁定關係。
- 客戶端投遞消息到exchange。
exchange接收到消息後,就根據消息的key和已經設置的binding,進行消息路由,將消息投遞到一個或多個隊列裏。
exchange也有幾個類型,完全根據key進行投遞的叫做Direct交換機,例如,綁定時設置了routing key爲”abc”,那麼客戶端提交的消息,只有設置了key爲”abc”的纔會投遞到隊列。對key進行模式匹配後進行投遞的叫做Topic交換機,符號”#”匹配一個或多個詞,符號”*”匹配正好一個詞。例如”abc.#”匹配”abc.def.ghi”,”abc.*”只匹配”abc.def”。還有一種不需要key的,叫做Fanout交換機,它採取廣播模式,一個消息進來時,投遞到與該交換機綁定的所有隊列。
RabbitMQ支持消息的持久化,也就是數據寫在磁盤上,爲了數據安全考慮,我想大多數用戶都會選擇持久化。消息隊列持久化包括3個部分:
exchange持久化,在聲明時指定durable => 1
queue持久化,在聲明時指定durable => 1
消息持久化,在投遞時指定delivery_mode => 2(1是非持久化)
如果exchange和queue都是持久化的,那麼它們之間的binding也是持久化的。如果exchange和queue兩者之間有一個持久化,一個非持久化,就不允許建立綁定。
rabbitmq官方說明文檔地址:
https://www.rabbitmq.com/getstarted.html
通信方式主要可以分爲兩種:
其一:點對點(即沒有交換機)
其二:發佈訂閱(有交換機exchange)
常用的兩種:
其一:Routing路由方式
其二:Topics比較靈活,路徑匹配
服務啓動及配置
首先啓動rabbitmq-server
service rabbitmq-server start
本地端口訪問: http://192.168.239.129:15672
訪問成功,則證明安裝成功。才能進入後續操作
創建一個新的用戶:
創建一個虛擬主機
設置虛擬主機的權限permissions,和用戶綁定
點擊虛擬主機的名字
選擇剛剛創建的用戶
退出登錄,用剛剛的用戶登錄成功即可
可參考:
https://blog.51cto.com/13877966/2297056
https://blog.csdn.net/qq_38455201/article/details/80308771
demo
導入依賴:
<dependencies>
<!--rabbitmq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
創建Send 生產者
package com.ldgroup.rabbitmqdemo.service;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Description
* @Author by mocar小師兄
* @Date 2020/4/25 0:58
**/
public class Send {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public static final String QUEUE_A = "QUEUE_A";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.239.129");
connectionFactory.setPort(5672);
connectionFactory.setUsername("mocar");
connectionFactory.setPassword("mocar");
connectionFactory.setVirtualHost("/mocar");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
//隊列聲明,隊列不存在則創建,否則不做處理
//exclusive:獨有的,是否只允許當前連接使用此隊列
channel.queueDeclare(QUEUE_A,true,false,false,null);
String msg="第一次發送消息rabbitmq";
channel.basicPublish("",QUEUE_A,null,msg.getBytes());
System.out.println("發送完成");
}
}
發送成功,產生一條帶消費的消息
創建Receiving消費者
package com.ldgroup.rabbitmqdemo.service;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Description
* @Author by mocar小師兄
* @Date 2020/4/25 1:56
**/
public class Receiving {
public static final String QUEUE_A = "QUEUE_A";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.239.129");
connectionFactory.setPort(5672);
connectionFactory.setUsername("mocar");
connectionFactory.setPassword("mocar");
connectionFactory.setVirtualHost("/mocar");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
//創建消費者
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
//等待隊列有消息之後,自動回調
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//super.handleDelivery(consumerTag, envelope, properties, body);
//消費消息
String msg = new String(body,"utf-8");
System.out.println("消費消息:\t" + msg);
}
};
//讓消費者監聽隊列
//消費後ACK確認消息成功消費
channel.basicConsume(QUEUE_A,true,defaultConsumer);
System.out.println("成功消費");
}
}
消息成功被消費