目錄
2.5 上圖5:主題模式 Topic Exchange (通配符模式)
1.基礎知識:
1.0 前言:
RabbitMQ是一個由erlang語言開發的基於AMQP(Advanved Message Queue)隊列協議的開源實現。
支持的操作系統 linux、windows、macox等
支持的開發語言 java、python、ruby、.net、php、c/c++、node.js等
1.1 rabbitmq的用戶角色
1、 超級管理員(administrator)
可登陸管理控制檯,可查看所有的信息,並且可以對用戶,策略(policy)進行操作。
2、 監控者(monitoring)
可登陸管理控制檯,同時可以查看rabbitmq節點的相關信息(進程數,內存使用情況,磁盤使用情況等)
3、 策略制定者(policymaker)
可登陸管理控制檯, 同時可以對policy進行管理。但無法查看節點的相關信息(上圖紅框標識的部分)。
4、 普通管理者(management)
僅可登陸管理控制檯,無法看到節點信息,也無法對策略進行管理。
5、 其他
無法登陸管理控制檯,通常就是普通的生產者和消費者。
1.2 rabbitmq的端口號
5672: AMQP協議的端口號(與Java交互)
15672: 管理工具的端口
25672: 集羣
這些端口需要防火牆放行,詳細的操作細節後面的linux、windows搭建會有提及
1.3 消息隊列的運行原理
從上圖可以看出、生產者、消息隊列、消費者是最重要的三個概念:
生產者(Producer):創建消息到消息隊列中(消息的創建者,負責創建和推送數據到消息服務器)。
消息隊列(Queue):存儲消息。
消費者(Consumer):監聽指定消息隊列,當消息隊列接收到消息後,獲取消息並處理。
RabbitMQ:創建消息隊列,並提供API給生產者和消費者進行存取消息,用於扮演“快遞”的角色,本身不生產消息,只是扮演“快遞”的角色。
生產者產生消息並調用RabbitMQ的API將消息加入到對應的消息隊列中,消費者通過RabbitMQ的API從消息隊列中獲取消息進行消費。
這裏面有一個虛擬機的概念,你可以把它理解爲域名,在應用中需要通過配置或者代碼指定你要用哪個虛擬機(Vhost)。如果你不指定,那麼默認的會選用 "/".前提是你的當前用戶有對這個虛擬機 "/" 的使用權限。虛擬機可以在rabbitmq的可視化頁面裏面配置。
1.4你必須知道的Rabbit
想要真正的瞭解Rabbit有些名詞是你必須知道的。
包括:ConnectionFactory(連接管理器)、Channel(信道)、Exchange(交換器)、Queue(隊列)、 RoutingKey(路由鍵)、BindingKey(綁定鍵)。
ConnectionFactory(連接管理器):應用程序與Rabbit之間建立連接的管理器,程序代碼中使用;
Channel(信道):消息推送使用的通道;
Exchange(交換器):用於接受、分配消息;
Queue(隊列):用於存儲生產者的消息;
RoutingKey(路由鍵):用於把生成者的數據分配到交換器上;
BindingKey(綁定鍵):用於把交換器的消息綁定到隊列上;
2.六種隊列
rabbitmq一共有六種隊列,其中RPC已被淘汰:
2.1 上圖1: 簡單隊列
生產者與消費者一一對應 生產者將消息發送到隊列,消費者從隊列中獲取消息。
在這種模式下一個生產者對應了多個消費者,但是一個消息只能被一個消費者獲取。可以配置消息分發到消費者的路由規則
“P”是我們的生產者,“C”是我們的消費者。中間的框是一個隊列。
生產者將消息發送到隊列,消費者從隊列中消費。
2.2 上圖2:Work模式
一個生產者多個消費者,每個消費者獲取到的消息唯一
2.3上圖3: 訂閱模式 Fanout Exchange
解讀:
1、1個生產者,多個消費者
2、每一個消費者都有自己的一個隊列
3、生產者沒有將消息直接發送到隊列,而是發送到了交換機
4、每個隊列都要綁定到交換機
5、生產者發送的消息,經過交換機,到達隊列,實現,一個消息被多個消費者獲取的目的
注意:一個消費者隊列可以有多個消費者實例,只有其中一個消費者實例會消費
fanout(不處理路由鍵):每個和交換機綁定的隊列都會收到消息
2.4上圖4: 路由模式 Direct Exchange
發送消息到交換機並且要指定路由key ,消費者將隊列綁定到交換機時需要指定路由key。它會把消息路由到那些binding key與routing key完全匹配的Queue中。
2.5 上圖5:主題模式 Topic Exchange (通配符模式)
這個可以理解爲隊列的模糊匹配。消息經過交換機推送到符合通配符規則的隊列中。
將路由鍵和某模式進行匹配,此時隊列需要綁定在一個模式上,“#”匹配一個詞或多個詞,“*”只匹配一個詞。當消息發送至交換機時,只有routingKey能夠滿足通配規則的隊列才能夠接收到消息。
例如:routingKey 爲 testqueue 的隊列 能夠接收到 test# 的消息
3.應用場景
3.1.延遲隊列
用戶註冊後長時間不活躍定時推送提醒
訂單下單後長時間未支付轉至推送提醒
延遲重試,比如服務原因導致業務執行終端通過延遲重試保障業務完整性等
3.2.消息錯峯
秒殺、促銷等大流量信息短時間注入是的錯峯處理以平衡上下游吞吐量
3.3.消息分發
統一消息源發送的消息應對不同的消費邏輯。如業務處理和日誌採集
3.4.應用解耦
通過發佈訂閱方式代替接口調用解耦項目
3.5.消息確認ACK
保障業務完整性 提供了confirm 和 return 兩種消息確認回調方法。
當消息由生產端成功發送至交換機 confirm回調方法會收到布爾類型的ack確認。true爲推送至交換機成功。
當消息由交換機根據routingKey推送至queue隊列中時,return回調方法會收到字符類型的replyText確認。
4.rabbitMq與Erlang版本對應關係
在搭建RabbitMQ環境過程中,由於版本問題導致環境一直搭建不起來,以下是RabbitMQ與Erlang的版本對應關係
RabbitMQ版本 |
Erlang最低要求 |
Erlang最高要求 |
3.7.7 - 3.7.12 |
20.3.x |
21.x |
3.7.0 - 3.7.6 |
19.3 |
20.3.x |
5.windows搭建
5.1安裝Erlang
5.1.1下載erlang
下載:http://www.erlang.org/download/otp_win64_17.3.exe
百度雲盤下載:https://pan.baidu.com/s/1-5yJGzOl23BuQl1D2_n3SA
5.1.2安裝erlang
安裝完成。
5.2安裝rabbitmq
5.2.1下載rabbitmq
官方下載地址:http://www.rabbitmq.com/download.html
百度雲盤下載: https://pan.baidu.com/s/18Dxi01D0sbjPZq-RWymnww
5.2.2安裝Rabbitmq
安裝完成。
5.2.3 啓用管理工具
cmd進入安裝目錄sbin文件夾下 輸入命令:
啓用管理頁面命令 rabbitmq-plugins enable rabbitmq_management
在瀏覽器中輸入地址查看:http://127.0.0.1:15672/
使用默認子賬號登錄:guest 密碼 guest
操作界面不再贅述。 至此 windows 環境搭建已全部完成。
6.linux搭建
6.1 說明:
搭建過程中遇到了mq包與linux系統版本衝突問題,故在此提供了 基於centos6 和centos7兩個版本系統的搭建步驟。
6.2CentOs6安裝:
6.2.1下載安裝包:
rabbitmq安裝包:https://pan.baidu.com/s/1pAkK81dFFojnO6fTIxhHkw
erlang安裝包:https://pan.baidu.com/s/1jWl-YUSSv1GBUJntZNgXDw
socat安裝包:https://pan.baidu.com/s/1DfbX4a4dxtBFA3ZQ7NYDBQ
6.2.2centos6安裝:
1.安裝erlang的rpm庫。
rpm -ivh erlang-20.3.8.7-1.el6.x86_64.rpm
判斷erlang是否安裝成功:命令行輸入 erl
有輸出即表示安裝成功
2.安裝socat依賴:
安裝socat的rpm庫。
yum install tcp_wrappers
rpm -ivh socat-1.7.3.0-1.el6.x86_64.rpm(不同版本號要修改)
3.安裝RabbitMQ
rpm -ivh rabbitmq-server-3.7.7-1.el6.noarch.rpm (不同版本號要修改)
4.啓動rabbitmq:service rabbitmq-server start/stop/restart
5.查看rabbitmq的啓動狀態 service rabbitmq-server status
6.RabbitMQ配置 這裏主要是創建用戶和賦權,因爲guest這個用戶 默認的只能本機訪問,而我們部署時一般不會放在同一臺機器上。創建了admin用戶後就可以去瀏覽器設置其他用戶了。
啓動RabbitMQ後執行:
1、rabbitmqctl add_user admin 123456(創建用戶)
2、rabbitmqctl set_user_tags admin administrator(將創建好的用戶加入管理員)
3、rabbitmqctl set_permissions -p "/" admin "." "." ".*"(授權)
4、rabbitmq-plugins enable rabbitmq_management 啓動RabbitMQ管理頁面(執行完這個才能用瀏覽器可視化網頁)
5、重啓MQ服務 service rabbitmq-server restart
6、開放5672/15672/25672端口。
vi /etc/sysconfig/iptables
在紅框處的下一行依次添加開放端口語句後保存:
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 5672-j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 15672-j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 25672-j ACCEPT
重啓防火牆:
service iptables restart
7、在瀏覽器輸入ip:15672後出現RabbitMQ管理臺。
6.3 centos7安裝:
方式一: rpm包安裝
1.1. 安裝依賴環境Erlang
使用Erlang Solutions源進行安裝
# 下載rpm包
wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
# 從erlang-solutions中更新該包,並將erlang_solutions.repo添加到/etc/yum.repos.d
rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
# 安裝
yum install erlang
該包還需依賴到epel源,請確保已有該源,若沒有則可通過以下方式安裝:
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm
yum repolist # 查看安裝是否成功
由於Erlang Solutions會進行不斷地更新,且RabbitMQ對Erlang的版本有一定的要求(官方版本要求對應表)。所以官方建議我們禁止Erlang版本的自動更新。方法如下:參考如何禁止某個軟件包的自動升級
# 安裝yum-versionlock
yum install yum-plugin-versionlock
# 禁止Erlang自動更新
yum versionlock erlang
1.2. 安裝RabbitMQ Server
從官網下載rpm包並上傳到服務器上。官方下載鏈接
# 導入簽名
rpm --import https://dl.bintray.com/rabbitmq/Keys/rabbitmq-release-signing-key.asc
# 或
rpm --import https://www.rabbitmq.com/rabbitmq-release-signing-key.asc
# 安裝
yum install rabbitmq-server-3.7.7-1.el7.noarch.rpm
方式二: 使用腳本安裝
2.1安裝erlang
#創建erlang.repo庫
curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash
#安裝
yum install erlang
2.2安裝rabbitmq
#創建rabbitmq-server.repo庫
curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.rpm.sh | sudo bash
#安裝
yum install rabbitmq-server
這種方式雖然會簡單點,但我嘗試過,發現只有翻牆才能安裝成功,所以不太推薦大家使用這種方法。
2.3. 啓動RabbitMQ Server
# 設置開啓啓動
chkconfig rabbitmq-server on
# 啓動服務
service rabbitmq-server start
#停止服務
service rabbitmq-server stop
#監測狀態
service rabbitmq-server status
#用戶賦權
rabbitmqctl add_user admin 123456(創建用戶)
rabbitmqctl set_user_tags admin administrator(將創建好的用戶加入管理員)
rabbitmqctl set_permissions -p "/" admin "." "." ".*"(授權)
2.4. 配置RabbitMQ
2.4.1 找到配置文件
/usr/share/doc/rabbitmq-server-3.7.7/ 目錄下複製一份模板到 /etc/rabbitmq 目錄下進行修改
cd /usr/share/doc/rabbitmq-server-3.7.7/
cp rabbitmq.config.example /etc/rabbitmq/rabbitmq.config
2.4.2 開啓管理後臺 centos7 防火牆 叫firewall了 不是iptables了啊 ,這個注意下。
rabbitmq-plugins enable rabbitmq_management
# 開放端口
firewall-cmd --add-port=5672/tcp --permanen
firewall-cmd --add-port=15672/tcp --permanen
firewall-cmd --add-port=25672/tcp --permanent
firewall-cmd --reload
6.4 瀏覽器訪問
http://ip:15672 ,進入如下頁面就證明插件啓動成功了
6.5 移除queue
清除的命令是: rabbitmqctl reset
但是在使用此命令前,要先關閉應用,否則不能清除。
關閉應用的命令爲: rabbitmqctl stop_app
執行了這兩條命令後再次啓動此應用。
命令爲: rabbitmqctl start_app
再次執行命令: rabbitmqctl list_queues
這次可以看到 listing 及 queues都是空的
7.與spingboot集成
7.1.配置rabbitmq連接信息:
application.properties中配置rabbitMQ的連接信息:
#對於rabbitMQ的支持
spring.rabbitmq.host=192.168.189.136
spring.rabbitmq.port=5672
spring.rabbitmq.username=yolly
spring.rabbitmq.password=yolly
spring.rabbitmq.virtualHost=yolly
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.template.mandatory=true
#併發消費者的初始化值,併發消費者的最大值,每個消費者每次監聽時可拉取處理的消息數量。
spring.rabbitmq.listener.concurrency=10
spring.rabbitmq.listener.max-concurrency=20
spring.rabbitmq.listener.prefetch=5
host、用戶名、密碼還有虛擬機名稱這三個需要改成你自己的rabbitmq主機ip和賬號密碼虛擬機哈。
這個虛擬機spring.rabbitmq.virtualHost可以不寫,如果不寫或者寫“” 他會選擇使用 “/” 虛擬機,前提是你的當前賬號有 “/” 虛擬機的使用權限。
7.2 添加AMQP支持
因爲rabbitmq是基於amqp協議開發的 所以需要在pom.xml中添加amqp dependencies:
同時用到了web測試效果,所以需要引用web starter
<!--amqp-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>RELEASE</version>
</dependency>
7.3定製化AMQP模板
上面我們提到了rabbitmq的消息ack機制,在boot工程中這個機制生效的前提是聲明confirm和return爲true ,且實現他們的回調方法:
/**
* 定製化amqp模版 可根據需要定製多個
* <p>
* <p>
* 此處爲模版類定義 Jackson消息轉換器
* ConfirmCallback接口用於實現消息發送到RabbitMQ交換器後接收ack回調 即消息發送到exchange ack
* ReturnCallback接口用於實現消息發送到RabbitMQ 交換器,但無相應隊列與交換器綁定時的回調 即消息發送不到任何一個隊列中 ack
*
* @return the amqp template
*/
// @Primary
@Bean
public AmqpTemplate amqpTemplate() {
Logger log = LoggerFactory.getLogger(RabbitTemplate.class);
// 使用jackson 消息轉換器
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
rabbitTemplate.setEncoding("UTF-8");
// 開啓returncallback yml 需要 配置 publisher-returns: true
rabbitTemplate.setMandatory(true);
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
String correlationId = message.getMessageProperties().getCorrelationId();
log.debug("消息:{} 發送失敗, 應答碼:{} 原因:{} 交換機: {} 路由鍵: {}", correlationId, replyCode, replyText, exchange, routingKey);
});
// 消息確認 yml 需要配置 publisher-returns: true
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
log.debug("消息發送到exchange成功,id: {}", correlationData.getId());
} else {
log.debug("消息發送到exchange失敗,原因: {}", cause);
}
});
return rabbitTemplate;
}
至此集成工作已經全部實現完畢了
7.4 direct類型
重定向模式 發送至exchange下滿足規則的queue
7.4.1定義direct類型隊列、交換機並綁定:
/* ----------------------------------------------------------------------------Direct exchange test--------------------------------------------------------------------------- */
/**
* 聲明直連交換機 支持持久化.
*
* @return the exchange
*/
@Bean("directExchange")
public Exchange directExchange() {
return ExchangeBuilder.directExchange("DIRECT_EXCHANGE").durable(true).build();
}
/**
* 聲明一個隊列 支持持久化.
*
* @return the queue
*/
@Bean("directQueueA")
public Queue directQueueA() {
return QueueBuilder.durable("DIRECT_QUEUE_A").build();
}
/**
* 聲明一個隊列 支持持久化.
*
* @return the queue
*/
@Bean("directQueueB")
public Queue directQueueB() {
return QueueBuilder.durable("DIRECT_QUEUE_B").build();
}
/**
* 通過綁定鍵 將指定隊列綁定到一個指定的交換機 .
*
* @param queue the queue
* @param exchange the exchange
* @return the binding
*/
@Bean
public Binding directBindingA(@Qualifier("directQueueA") Queue queue, @Qualifier("directExchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("DIRECT_ROUTING_KEY_A").noargs();
}
/**
* 通過綁定鍵 將指定隊列綁定到一個指定的交換機 .
*
* @param queue the queue
* @param exchange the exchange
* @return the binding
*/
@Bean
public Binding directBindingB(@Qualifier("directQueueB") Queue queue, @Qualifier("directExchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("DIRECT_ROUTING_KEY_B").noargs();
}
7.4.2 controller中發送消息
/**
* 測試Direct模式.
*direct類型的Exchange路由規則也很簡單,它會把消息路由到那些binding key與routing key完全匹配的Queue中
* @param p the p
* @return the response entity
*/
@RequestMapping("/direct")
public ResponseEntity direct(String p) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
//routing key爲一個句點號“. ”分隔的字符串(我們將被句點號“. ”分隔開的每一段獨立的字符串稱爲一個單詞),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
//binding key與routing key一樣也是句點號“. ”分隔的字符串
//binding key中可以存在兩種特殊字符“*”與“#”,用於做模糊匹配,其中“*”用於匹配一個單詞,“#”用於匹配多個單詞(可以是零個)
// 如果寫成 "DIRECT_ROUTING_KEY_.*" 則爲topic模式 即模糊匹配
rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "DIRECT_ROUTING_KEY_A", p, correlationData);
return ResponseEntity.ok();
}
7.4.3 receiver端接收消息
/**
* DIRECT模式.
*
* @param message the message
* @param channel the channel
* @throws IOException the io exception 這裏異常需要處理
*/
@RabbitListener(queues = {"DIRECT_QUEUE_A"})
public void messageA(Message message, Channel channel) throws IOException {
log.debug("DIRECTA "+new String (message.getBody()));
}
/**
* DIRECT模式.
*
* @param message the message
* @param channel the channel
* @throws IOException the io exception 這裏異常需要處理
*/
@RabbitListener(queues = {"DIRECT_QUEUE_B"})
public void messageB(Message message, Channel channel) throws IOException {
log.debug("DIRECTB "+new String (message.getBody()));
}
只有隊列A能夠存儲消息、消費者A能夠收到消息
7.5 fanout類型
廣播模式 發送到exchange下所有的queue
7.5.1定義fanout類型隊列、交換機並綁定:
/* ----------------------------------------------------------------------------Fanout exchange test--------------------------------------------------------------------------- */
/**
* 聲明 fanout 交換機.
*
* @return the exchange
*/
@Bean("fanoutExchange")
public FanoutExchange fanoutExchange() {
return (FanoutExchange) ExchangeBuilder.fanoutExchange("FANOUT_EXCHANGE").durable(true).build();
}
/**
* Fanout queue A.
*
* @return the queue
*/
@Bean("fanoutQueueA")
public Queue fanoutQueueA() {
return QueueBuilder.durable("FANOUT_QUEUE_A").build();
}
/**
* Fanout queue B .
*
* @return the queue
*/
@Bean("fanoutQueueB")
public Queue fanoutQueueB() {
return QueueBuilder.durable("FANOUT_QUEUE_B").build();
}
/**
* 綁定隊列A 到Fanout 交換機.
*
* @param queue the queue
* @param fanoutExchange the fanout exchange
* @return the binding
*/
@Bean
public Binding bindingA(@Qualifier("fanoutQueueA") Queue queue, @Qualifier("fanoutExchange") FanoutExchange fanoutExchange) {
return BindingBuilder.bind(queue).to(fanoutExchange);
}
/**
* 綁定隊列B 到Fanout 交換機.
*
* @param queue the queue
* @param fanoutExchange the fanout exchange
* @return the binding
*/
@Bean
public Binding bindingB(@Qualifier("fanoutQueueB") Queue queue, @Qualifier("fanoutExchange") FanoutExchange fanoutExchange) {
return BindingBuilder.bind(queue).to(fanoutExchange);
}
7.5.2 controller中發送消息
/**
* 測試廣播模式.
* fanout類型的Exchange路由規則非常簡單,它會把所有發送到該Exchange的消息路由到所有與它綁定的Queue中。
* @param p the p
* @return the response entity
*/
@RequestMapping("/fanout")
public ResponseEntity send(String p) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("FANOUT_EXCHANGE", "", p, correlationData);
return ResponseEntity.ok();
}
7.5.3 receiver端接收消息
/**
* FANOUT廣播隊列監聽一.
*
* @param message the message
* @param channel the channel
* @throws IOException the io exception 這裏異常需要處理
*/
@RabbitListener(queues = {"FANOUT_QUEUE_A"})
public void on(Message message, Channel channel) throws IOException {
log.debug("FANOUT_QUEUE_A "+new String(message.getBody()));
}
/**
* FANOUT廣播隊列監聽二.
*
* @param message the message
* @param channel the channel
* @throws IOException the io exception 這裏異常需要處理
*/
@RabbitListener(queues = {"FANOUT_QUEUE_B"})
public void t(Message message, Channel channel) throws IOException {
log.debug("FANOUT_QUEUE_B "+new String(message.getBody()));
}
AB 都能接收到消息
7.6 diedletter類型(延遲消費類型)
A隊列接收 過期後轉發至B隊列 B隊列被消費 實現消息的延遲消費
原理圖:
7.6.1定義diedletter類型隊列、交換機並綁定:
/*----------------------------------------------------------------------------deadletter queue------------------------------------------------------------------------------*/
/**
* 死信隊列跟交換機類型沒有關係 不一定爲directExchange 不影響該類型交換機的特性.
*
* @return the exchange
*/
@Bean("deadLetterExchange")
public Exchange deadLetterExchange() {
return ExchangeBuilder.directExchange("DL_EXCHANGE").durable(true).build();
}
/**
* 聲明一個死信隊列.
* x-dead-letter-exchange 對應 死信交換機
* x-dead-letter-routing-key 對應 死信隊列
*
* @return the queue
*/
@Bean("deadLetterQueue")
public Queue deadLetterQueue() {
Map<String, Object> args = new HashMap<>(2);
// x-dead-letter-exchange 聲明 死信交換機
args.put(DEAD_LETTER_QUEUE_KEY, "DL_EXCHANGE");
// x-dead-letter-routing-key 聲明 死信路由鍵
args.put(DEAD_LETTER_ROUTING_KEY, "KEY_R");
return QueueBuilder.durable("DL_QUEUE").withArguments(args).build();
}
/**
* 定義死信隊列轉發隊列.
*
* @return the queue
*/
@Bean("redirectQueue")
public Queue redirectQueue() {
return QueueBuilder.durable("REDIRECT_QUEUE").build();
}
/**
* 死信路由通過 DL_KEY 綁定鍵綁定到死信隊列上.
*
* @return the binding
*/
@Bean
public Binding deadLetterBinding() {
return new Binding("DL_QUEUE", Binding.DestinationType.QUEUE, "DL_EXCHANGE", "DL_KEY", null);
}
/**
* 死信路由通過 KEY_R 綁定鍵綁定到死信隊列上.
*
* @return the binding
*/
@Bean
public Binding redirectBinding() {
return new Binding("REDIRECT_QUEUE", Binding.DestinationType.QUEUE, "DL_EXCHANGE", "KEY_R", null);
}
7.6.2 controller中發送消息
/**
* 測試死信隊列.
*
* @param p the p
* @return the response entity
*/
@RequestMapping("/dead")
public ResponseEntity deadLetter(String p) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
// 聲明消息處理器 這個對消息進行處理 可以設置一些參數 對消息進行一些定製化處理 我們這裏 來設置消息的編碼 以及消息的過期時間 因爲在.net 以及其他版本過期時間不一致 這裏的時間毫秒值 爲字符串
MessagePostProcessor messagePostProcessor = message -> {
MessageProperties messageProperties = message.getMessageProperties();
// 設置編碼
messageProperties.setContentEncoding("utf-8");
// 設置過期時間10*1000毫秒
messageProperties.setExpiration("2000");
return message;
};
// 向DL_QUEUE 發送消息 10*1000毫秒後過期 形成死信
rabbitTemplate.convertAndSend("DL_EXCHANGE", "DL_KEY", p, messagePostProcessor, correlationData);
return ResponseEntity.ok();
}
7.6.3 receiver端接收消息
/**
* 監聽替補隊列 來驗證死信.
*
* @param message the message
* @param channel the channel
* @throws IOException the io exception 這裏異常需要處理
*/
@RabbitListener(queues = {"REDIRECT_QUEUE"})
public void redirect(Message message, Channel channel) throws IOException {
log.debug("dead message 10s 後 消費消息 {}",new String (message.getBody()));
}
過一會替補隊列接收到了消息
7.7 topic類型
模糊匹配模式 這個routingkey與bindingkey採用正則通配符形式模糊匹配
7.7.1定義topic類型隊列、交換機並綁定:
同7.4.1
7.7.2 controller中發送消息
/**
* 測試Direct模式.
*direct類型的Exchange路由規則也很簡單,它會把消息路由到那些binding key與routing key完全匹配的Queue中
* @param p the p
* @return the response entity
*/
@RequestMapping("/direct")
public ResponseEntity direct(String p) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
//routing key爲一個句點號“. ”分隔的字符串(我們將被句點號“. ”分隔開的每一段獨立的字符串稱爲一個單詞),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
//binding key與routing key一樣也是句點號“. ”分隔的字符串
//binding key中可以存在兩種特殊字符“*”與“#”,用於做模糊匹配,其中“*”用於匹配一個單詞,“#”用於匹配多個單詞(可以是零個)
// 如果寫成 "DIRECT_ROUTING_KEY_.*" 則爲topic模式 即模糊匹配
rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "DIRECT_ROUTING_KEY_.*", p, correlationData);
return ResponseEntity.ok();
}
7.7.3 receiver端接收消息
同7.4.3
這個時候AB隊列都能夠收到消息,且他們的監聽這也能監聽到同樣的消息
8.上代碼
這個源碼親測可用的哈,下載後直接瀏覽器調用controller對應的demo就能看驗證效果了
下載地址:https://pan.baidu.com/s/1J3JQoyNv0_gfiy_p3hrZZg