SpringAMQP 的發布方確認

前言

這里的發布方確認是以 SpringAMQP 寫的,之前我們在前面的篇章中就學過了 使用 Java 原生的SDK編寫,當時是發布確認模式,在這里我們將用 Spring 集成的 rabbitmq 方法來編寫

開啟發布者確認機制需要進行下面的配置,以 yml 為例:

spring:rabbitmq:publisher-confirm-type: correlated   #消息發送確認

在使用RabbitMQ的時候,可以通過消息持久化來解決因為服務器的異常崩潰而導致的消息丟失,但是還有一個問題,當消息的生產者將消息發送出去之后,消息到底有沒有正確地到達服務器呢?

如果在消息到達服務器之前已經丟失(比如RabbitMQ重啟,那么RabbitMQ重啟期間生產者消息投遞失敗),持久化操作也解決不了這個問題,因為消息根本沒有到達服務器,何談持久化?
RabbitMQ為我們提供了兩種解決方案:
a.通過事務機制實現
b.通過發送方確認(publisherconfirm)機制實現

事務機制比較消耗性能,在實際工作中使用也不多,咱們主要介紹confirm機制來實現發送方的確認.
RabbitMQ為我們提供了兩個方式來控制消息的可靠性投遞
1.confirm確認模式
2. return退回模式

我們提前準備一下交換機和隊列:

    //發送方確認public static final String CONFIRM_QUEUE = "CONFIRM_QUEUE";public static final String CONFIRM_EXCHANGE = "CONFIRM_EXCHANGE";public static final String CONFIRM_ROUTING_KEY = "CONFIRM_ROUTING_KEY";
    //發送方確認@Bean("confirmQueue")public Queue confirmQueue() {return QueueBuilder.durable(MQConstants.CONFIRM_QUEUE).build();}@Bean("confirmExchange")public Exchange confirmExchange() {return ExchangeBuilder.directExchange(MQConstants.CONFIRM_EXCHANGE).durable(true).build();}@Bean("confirmBinding")public Binding confirmBinding(@Qualifier("confirmExchange") Exchange exchange, @Qualifier("confirmQueue") Queue queue) {return BindingBuilder.bind(queue).to(exchange).with(MQConstants.CONFIRM_ROUTING_KEY).noargs();}

confirm

Producer在發送消息的時候,對發送端設置一個ConfirmCallback的監聽,無論消息是否到達
Exchange,這個監聽都會被執行,如果Exchange成功收到,ACK(Acknowledgecharacter,確認
字符)為true,如果沒收到消息,ACK就為false.

confirm 模式是用于確認發送方的消息是否到達交換機

要啟動 confirm ,我們還需要創建一個新的 RabbitTemplate,通過rabbitTemplate.setConfirmCallback 來進行設置,ack 有兩種返回值,true和false,根據不同的返回值做不同的處理

@Configuration
public class RabbitTemplateConfig {/*** 構建原生的 RabbitTemplate* @param connectionFactory* @return*/@Bean("rabbitTemplate")public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {return new RabbitTemplate(connectionFactory);}/*** 構建發布方確認的 RabbitTemplate* @param connectionFactory* @return*/@Bean("confirmRabbitTemplate")public RabbitTemplate confirmRabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);//設置回調方法rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){@Overridepublic void confirm(CorrelationData correlationData, boolean ack, String cause) {System.out.println("調用了 confirm 方法");if(ack){System.out.printf("消息發送成功,消息ID:%s \n", correlationData == null ? null : correlationData.getId());}else {System.out.printf("消息發送失敗, 消息ID:%s, cause: %s \n", correlationData == null ? null :correlationData.getId(), cause);//響應的業務處理,如重發消息等等...}}});return rabbitTemplate;}
}

這里如果項目需要使用到原始的 RabbitTemplate 的話,需要創建一個,因為在你自定義創建過 RabbitTmeplate 的時候,Spring 就不會自動幫你創建原始的 RabbitTemplate 了。

參數介紹:

public void confirm(CorrelationData correlationData, boolean ack, String cause)

correlationData是消息的唯一標識,也就說序列號,我們可以通過生產者那邊進行設置,注意這里和消費者那邊的 deliveryTag 是不一樣的,correlationData是生產者使用的,deliveryTag 是隊列創建的

ack 是否確認消息達到
cause 存儲消息發送失敗的原因

我們來演示消息發送失敗的場景:

    @RequestMapping("/confirm")public String confirm() {for (int i = 0; i < 10; i++) {CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());confirmRabbitTemplate.convertAndSend(MQConstants.CONFIRM_EXCHANGE, "hello", "confirm: " + i, correlationData);}return "消息發送成功";}

我們將 routingkey 設置錯誤,觀察效果:
在這里插入圖片描述
我們會發現消息發送成功,這是因為消息確實達到的指定的交換機,但是我們查看隊列的時候是沒有消息的,因此進一步驗證了 confirm 模式只是確認消息是否達到交換機,并不能確認是否到達指定的隊列


接下來我們來指定一個不存在的交換機:

    @RequestMapping("/confirm")public String confirm() {for (int i = 0; i < 10; i++) {CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());confirmRabbitTemplate.convertAndSend("hello 85246", MQConstants.CONFIRM_ROUTING_KEY, "confirm: " + i, correlationData);}return "消息發送成功";}

在這里插入圖片描述
在 cause 的打印信息中:得知隊列不存在,因此 confirm 確實可以驗證消息有沒有達到指定的交換機里

returns

消息到達Exchange之后,會根據路由規則匹配,把消息放入Queue中.Exchange到Queue的過程,如果一條消息無法被任何隊列消費(即沒有隊列與消息的路由鍵匹配或隊列不存在等),可以選擇把消息退回給發送者,消息退回給發送者時,我們可以設置一個返回回調方法,對消息進行處理

簡單來說,returns 是確認交換機上的消息是否成功到達隊列上的

    @Bean("returnRabbitTemplate")public RabbitTemplate returnRabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setMandatory(true);rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {@Overridepublic void returnedMessage(ReturnedMessage returned) {System.out.println("調用了 returnedMessage 方法");System.out.printf("消息被退回:%s \n", returned);}});return rabbitTemplate;}

使用RabbitTemplate的setMandatory方法設置消息的mandatory屬性為true(默認為false).這個屬性的作用是告訴RabbitMQ,如果一條消息無法被任何隊列消費,RabbitMQ應該將消息返回給發送者,此時ReturnCallback就會被觸發.

如果我們指定一個不存在的 routingkey,那就沒有隊列能接收到消息,就會觸發ReturnsCallback方法
在這里插入圖片描述

合并使用

當然這兩個模式是可以一起使用的,代碼演示:

    /*** 構建發布方確認的 RabbitTemplate* @param connectionFactory* @return*/@Bean("confirmRabbitTemplate")public RabbitTemplate confirmRabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);//設置回調方法rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){@Overridepublic void confirm(CorrelationData correlationData, boolean ack, String cause) {System.out.println("調用了 confirm 方法");if(ack){System.out.printf("消息發送成功,消息ID:%s \n", correlationData == null ? null : correlationData.getId());}else {System.out.printf("消息發送失敗, 消息ID:%s, cause: %s \n", correlationData == null ? null :correlationData.getId(), cause);//響應的業務處理,如重發消息等等...}}});//設置消息退回回調rabbitTemplate.setMandatory(true);rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {@Overridepublic void returnedMessage(ReturnedMessage returned) {System.out.println("調用了 returnedMessage 方法");System.out.printf("消息被退回:%s \n", returned);}});return rabbitTemplate;}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96250.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96250.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96250.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一套自用的git提交規范,可清晰的識別到關聯的任務/bug

分享一套自用的git提交規范&#xff0c;可清晰的識別到關聯的任務/bug 一、提交信息的基本結構 推薦使用約定式提交的一種變體&#xff0c;結構如下&#xff1a; <類型>(<范圍>): <主題> [#<禪道-ID>]<正文>&#xff08;可選&#xff09;<腳注…

從音頻到文本實現高精度離線語音識別

會議頻繁&#xff0c;記錄繁瑣&#xff1f;語音轉換成文字工具價格高昂&#xff0c;自己手動整理又耗時費力&#xff1f; 它支持本地離線運行&#xff0c;無需聯網&#xff0c;所有數據留在本地&#xff0c;隱私安全毫無顧慮&#xff0c;同時它的功能是實時語音轉文字&#xf…

SpringMVC 工作原理

SpringMVC 工作原理 SpringMVC 是 Spring 框架中用于構建 Web 應用的核心模塊&#xff0c;其工作流程圍繞 “前端控制器&#xff08;DispatcherServlet&#xff09;” 展開&#xff0c;通過組件間的協作完成請求處理與響應。理解其工作原理是掌握 SpringMVC 開發的關鍵&#xf…

HoRain云--Python機器學習神器:Sklearn全解析

&#x1f3ac; HoRain云小助手&#xff1a;個人主頁 &#x1f525; 個人專欄: 《Linux 系列教程》《c語言教程》 ??生活的理想&#xff0c;就是為了理想的生活! ?? 推薦 前些天發現了一個超棒的服務器購買網站&#xff0c;性價比超高&#xff0c;大內存超劃算&#xff01;…

瘋狂星期四文案網第64天運營日記

網站運營第64天&#xff0c;點擊觀站&#xff1a; 瘋狂星期四 crazy-thursday.com 全網最全的瘋狂星期四文案網站 運營報告 今日訪問量 今日搜索引擎收錄情況

設計一個 AB 測試平臺

1. 需求明確化 功能需求實驗管理 創建、編輯、刪除、復制實驗設置實驗參數&#xff08;變體、權重、目標指標、時長等&#xff09;實驗狀態管理&#xff08;草稿、運行中、已結束&#xff09;用戶分流與分配 支持多種分流策略&#xff08;隨機分配、分層分配、定向分配&#xf…

HiCMAE 論文復現:基于 RAVDESS 數據集的音視頻情感識別

HiCMAE 論文復現:基于 RAVDESS 數據集的音視頻情感識別 1. 項目背景與論文概述 1.1 多模態情感識別背景 多模態情感識別是人工智能領域的重要研究方向,旨在通過結合多種感知模態(如音頻、視頻、文本等)來更準確地識別人類情感狀態。與傳統單模態方法相比,多模態方法能夠…

HarmonyOS 數據處理性能優化:算法 + 異步 + 分布式實戰

摘要 不管是寫 App&#xff0c;還是做 IoT 設備開發&#xff0c;數據處理都是繞不開的主題。你可能要處理幾百條傳感器數據&#xff0c;也可能要應對幾十萬條用戶行為日志。如果算法不夠高效&#xff0c;應用就會卡頓甚至直接崩潰。尤其是在 HarmonyOS&#xff08;鴻蒙系統&…

華為麒麟操作系統運維常見知識點

1.開放root賬號密碼登錄。(1)修改/etc/ssh/sshd_config文件中&#xff0c;PermitRootLogin 屬性值為yes。PermitRootLogin yes(2)使用passwd命令設置root密碼。sudo su 切換到root賬戶下&#xff0c;使用passwd 設置密碼。(3)重啟sshd服務。systemctl restart sshd2.避免使用ch…

嵌入式面試|MCU+RTOS技術棧——面試八股文整理3:STM32

目錄 1.單片機啟動流程 2.看門狗 3.最小系統 4.ROM、RAM、Flash 5.EPROM、EEPROM 6.Bootloader與OTA 7.NAND FLASH 和NOR FLASH 相同點 區別 適用場景 8.CPU、MPU、MCU、SOC、SOPC 9.交叉編譯 10.寄存器 寄存器的作用 寄存器與內存的區別 11.Cortex-M3寄存器組…

用 Wisdom SSH 輕松實現服務器自動化任務調度

用Wisdom SSH輕松實現服務器自動化任務調度 在服務器管理工作中&#xff0c;自動化任務調度至關重要&#xff0c;它能讓系統在特定時間自動執行預設任務&#xff0c;極大提升運維效率。Wisdom SSH作為一款具備AI助手的強大工具&#xff0c;為自動化任務調度帶來便捷解決方案。 …

遠場學習_FDTD_dipole(1)

項目4.4 Reflection calculation using a dipole source在此頁面中&#xff0c;我們采用了一種不同于標準平面波源方法的替代模擬設置&#xff0c;使用偶極子源來計算多層堆疊結構的反射。在此情況下&#xff0c;我們使用空氣 - 玻璃界面。這種技術很有吸引力&#xff0c;因為它…

機器學習入門,用Lima在macOS免費搭建Docker環境,徹底解決鏡像與收費難題!

國內用戶必看】用Lima在macOS免費搭建Docker環境&#xff0c;徹底解決鏡像與收費難題&#xff01; 為了在不同操作系統有一致操作體驗&#xff0c;我選擇使用docker技術安裝ollama&#xff0c;這樣子還有一個好處&#xff0c;即使玩壞了&#xff0c;刪除重建即可&#xff0c;所…

Java 生成簽名證書

在Java中生成簽名證書通常涉及到使用Java密鑰和證書管理工具&#xff08;Java Key and Certificate Management API&#xff0c;即Java Keytool&#xff09;。這個過程通常包括創建密鑰庫&#xff08;KeyStore&#xff09;&#xff0c;生成密鑰對&#xff08;Key Pair&#xff…

語法分析:編譯器中的“語法警察”

在編程的世界里&#xff0c;每一種編程語言都有自己的語法規則。就像中文有標點符號和語序規則一樣&#xff0c;編程語言也有自己嚴格的語法規則。語法分析器就像一個嚴格的"語法警察"&#xff0c;它的職責是檢查源代碼是否符合語言規范&#xff0c;同時為后續的處理…

容器的定義及工作原理

定義 你可以把 容器 想象成一個 “打包好的軟件快遞箱”。 里面有什么&#xff1f; 這個箱子里不僅裝著你的軟件&#xff08;比如一個網站程序&#xff09;&#xff0c;還把軟件運行所需要的所有東西都打包進去了&#xff0c;比如它需要哪個版本的Python、需要哪些系統文件、配…

云服務掃盲筆記(2) —— SLS 接入與設置自動化

前篇我們學習了SLS的核心用途及概念&#xff0c;本篇以將一個linux服務器的json格式日志接入阿里云SLS為例&#xff0c;繼續學習SLS接入中的關鍵設置及注意事項&#xff0c;以及如何將其實現簡單自動化快速操作。 一、 SLS 日志接入流程 [1] 準備工作&#xff08;確定日志路徑…

LwIP入門實戰 — 6 LwIP 網絡數據包

目錄 6.1 pbuf結構體 6.2 pbuf 的類型 6.2.1 PBUF_RAM 類型的pbuf 6.2.2 PBUF_POOL 類型的pbuf 6.2.3 PBUF_ROM 和 PBUF_REF 類型pbuf 6.3 pbuf 6.3.1 pbuf_alloc() 6.3.2 pbuf_free() 6.4 其它pbuf 操作函數 6.5 網卡中使用的 pbuf 6.5.1 low_level_output() 6.5.…

【已解決】Linux中程序腳本可以手動執行成功,但加在rc.local中不能開機自啟

之前開發遇到的一個問題&#xff1a;在Linux中&#xff0c;明明程序腳本可以手動執行成功&#xff0c;但加到開機自啟動里&#xff0c;卻會失敗&#xff0c;屬實讓人摸不著頭腦。 問題排查&#xff1a; 有以下幾種可能&#xff1a; 自啟動腳本&#xff0c;執行權限不足或者腳本…

切塊、清洗、烹飪:RAG知識庫構建的三步曲

嘿&#xff0c;各位AI技術愛好者們&#xff0c;你是不是經常遇到這樣的情況&#xff1a;辛辛苦苦訓練的AI助手&#xff0c;面對專業問題時卻"一問三不知"或者"胡言亂語"&#xff1f;明明你已經喂了它一堆PDF和Word文檔&#xff0c;為啥它就是不會用&#x…