最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Springboot結合rabbitmq實現(xiàn)的死信隊列

 更新時間:2023年09月05日 09:16:04   作者:西安未央  
為了保證訂單業(yè)務的消息數(shù)據(jù)不丟失,需要使用到RabbitMQ的死信隊列機制,本文主要介紹了Springboot結合rabbitmq實現(xiàn)的死信隊列,具有一定的參考價值,感興趣的可以了解一下

概述

RabbitMQ是流行的開源消息隊列系統(tǒng),使用erlang語言開發(fā)。為了保證訂單業(yè)務的消息數(shù)據(jù)不丟失,需要使用到RabbitMQ的死信隊列機制,當消息消費發(fā)生異常時,將消息投入死信隊列中。但由于對死信隊列的概念及配置不熟悉,導致曾一度陷入百度的汪洋大海,無法自拔,很多文章都看起來可行,但是實際上卻并不能幫我解決實際問題。最終,在官網(wǎng)文檔中找到了我想要的答案,通過官網(wǎng)文檔的學習,才發(fā)現(xiàn)對于死信隊列存在一些誤解,導致配置死信隊列之路困難重重。

詳細

一、運行效果

image.png

image.png

二、實現(xiàn)過程

①、先創(chuàng)建一個Springboot項目。然后在pom文件中添加  spring-boot-starter-amqp  和  spring-boot-starter-web 的依賴,接下來創(chuàng)建一個Config類,這里是關鍵:

package com.zyf.rabbitmqdeadletterdemo.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class RabbitMQConfig {
    public static final String BUSINESS_EXCHANGE_NAME = "rabbitmq.dead.letter.business.exchange";
    public static final String BUSINESS_QUEUEA_NAME = "rabbitmq.dead.letter.business.queueA";
    public static final String BUSINESS_QUEUEB_NAME = "rabbitmq.dead.letter.business.queueB";
    public static final String DEAD_LETTER_EXCHANGE = "rabbitmq.dead.letter.deadletter.exchange";
    public static final String DEAD_LETTER_QUEUEA_ROUTING_KEY = "rabbitmq.dead.letter.deadletter.queueA.routingkey";
    public static final String DEAD_LETTER_QUEUEB_ROUTING_KEY = "rabbitmq.dead.letter.deadletter.queueB.routingkey";
    public static final String DEAD_LETTER_QUEUEA_NAME = "rabbitmq.dead.letter.deadletter.queueA";
    public static final String DEAD_LETTER_QUEUEB_NAME = "rabbitmq.dead.letter.deadletter.queueB";
    // 聲明業(yè)務Exchange
    @Bean("businessExchange")
    public FanoutExchange businessExchange(){
        return new FanoutExchange(BUSINESS_EXCHANGE_NAME);
    }
    // 聲明死信Exchange
    @Bean("deadLetterExchange")
    public DirectExchange deadLetterExchange(){
        return new DirectExchange(DEAD_LETTER_EXCHANGE);
    }
    // 聲明業(yè)務隊列A
    @Bean("businessQueueA")
    public Queue businessQueueA(){
        Map<String, Object> args = new HashMap<>(2);
//       x-dead-letter-exchange    這里聲明當前隊列綁定的死信交換機
        args.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);
//       x-dead-letter-routing-key  這里聲明當前隊列的死信路由key
        args.put("x-dead-letter-routing-key", DEAD_LETTER_QUEUEA_ROUTING_KEY);
        return QueueBuilder.durable(BUSINESS_QUEUEA_NAME).withArguments(args).build();
    }
    // 聲明業(yè)務隊列B
    @Bean("businessQueueB")
    public Queue businessQueueB(){
        Map<String, Object> args = new HashMap<>(2);
//       x-dead-letter-exchange    這里聲明當前隊列綁定的死信交換機
        args.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);
//       x-dead-letter-routing-key  這里聲明當前隊列的死信路由key
        args.put("x-dead-letter-routing-key", DEAD_LETTER_QUEUEB_ROUTING_KEY);
        return QueueBuilder.durable(BUSINESS_QUEUEB_NAME).withArguments(args).build();
    }
    // 聲明死信隊列A
    @Bean("deadLetterQueueA")
    public Queue deadLetterQueueA(){
        return new Queue(DEAD_LETTER_QUEUEA_NAME);
    }
    // 聲明死信隊列B
    @Bean("deadLetterQueueB")
    public Queue deadLetterQueueB(){
        return new Queue(DEAD_LETTER_QUEUEB_NAME);
    }
    // 聲明業(yè)務隊列A綁定關系
    @Bean
    public Binding businessBindingA(@Qualifier("businessQueueA") Queue queue,
                                    @Qualifier("businessExchange") FanoutExchange exchange){
        return BindingBuilder.bind(queue).to(exchange);
    }
    // 聲明業(yè)務隊列B綁定關系
    @Bean
    public Binding businessBindingB(@Qualifier("businessQueueB") Queue queue,
                                    @Qualifier("businessExchange") FanoutExchange exchange){
        return BindingBuilder.bind(queue).to(exchange);
    }
    // 聲明死信隊列A綁定關系
    @Bean
    public Binding deadLetterBindingA(@Qualifier("deadLetterQueueA") Queue queue,
                                      @Qualifier("deadLetterExchange") DirectExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with(DEAD_LETTER_QUEUEA_ROUTING_KEY);
    }
    // 聲明死信隊列B綁定關系
    @Bean
    public Binding deadLetterBindingB(@Qualifier("deadLetterQueueB") Queue queue,
                                      @Qualifier("deadLetterExchange") DirectExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with(DEAD_LETTER_QUEUEB_ROUTING_KEY);
    }
}

②、接下來,是業(yè)務隊列的消費代碼:

@Slf4j@Componentpublic class BusinessMessageReceiver {    @RabbitListener(queues = BUSINESS_QUEUEA_NAME)
    public void receiveA(Message message, Channel channel) throws IOException {
        String msg = new String(message.getBody());
        log.info("收到業(yè)務消息A:{}", msg);        boolean ack = true;
        Exception exception = null;        try {            if (msg.contains("deadletter")){                throw new RuntimeException("dead letter exception");
            }
        } catch (Exception e){
            ack = false;
            exception = e;
        }        if (!ack){
            log.error("消息消費發(fā)生異常,error msg:{}", exception.getMessage(), exception);
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
        } else {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }    @RabbitListener(queues = BUSINESS_QUEUEB_NAME)
    public void receiveB(Message message, Channel channel) throws IOException {
        System.out.println("收到業(yè)務消息B:" + new String(message.getBody()));
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}

③、然后配置死信隊列的消費者:

@Componentpublic class DeadLetterMessageReceiver {    @RabbitListener(queues = DEAD_LETTER_QUEUEA_NAME)
    public void receiveA(Message message, Channel channel) throws IOException {
        System.out.println("收到死信消息A:" + new String(message.getBody()));
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }    @RabbitListener(queues = DEAD_LETTER_QUEUEB_NAME)
    public void receiveB(Message message, Channel channel) throws IOException {
        System.out.println("收到死信消息B:" + new String(message.getBody()));
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}

④、為了方便測試,寫一個簡單的消息生產者,并通過controller層來生產消息。

@Componentpublic class BusinessMessageSender {    @Autowired
    private RabbitTemplate rabbitTemplate;    public void sendMsg(String msg){
        rabbitTemplate.convertSendAndReceive(BUSINESS_EXCHANGE_NAME, "", msg);
    }
}
@RequestMapping("rabbitmq")@RestControllerpublic class RabbitMQMsgController {    @Autowired
    private BusinessMessageSender sender;    @RequestMapping("sendmsg")
    public void sendMsg(String msg){
        sender.sendMsg(msg);
    }
}

三、項目結構圖

image.png

四、補充總結

死信隊列其實并沒有什么神秘的地方,不過是綁定在死信交換機上的普通隊列,而死信交換機也只是一個普通的交換機,不過是用來專門處理死信的交換機。

總結一下死信消息的生命周期:

  • 業(yè)務消息被投入業(yè)務隊列
  • 消費者消費業(yè)務隊列的消息,由于處理過程中發(fā)生異常,于是進行了nck或者reject操作
  • 被nck或reject的消息由RabbitMQ投遞到死信交換機中
  • 死信交換機將消息投入相應的死信隊列
  • 死信隊列的消費者消費死信消息

死信消息是RabbitMQ為我們做的一層保證,其實我們也可以不使用死信隊列,而是在消息消費異常時,將消息主動投遞到另一個交換機中,當你明白了這些之后,這些Exchange和Queue想怎樣配合就能怎么配合。比如從死信隊列拉取消息,然后發(fā)送郵件、短信、釘釘通知來通知開發(fā)人員關注?;蛘邔⑾⒅匦峦哆f到一個隊列然后設置過期時間,來進行延時消費。

到此這篇關于Springboot結合rabbitmq實現(xiàn)的死信隊列的文章就介紹到這了,更多相關Springboot rabbitmq死信隊列內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java實現(xiàn)圖片上傳到服務器并把上傳的圖片讀取出來

    Java實現(xiàn)圖片上傳到服務器并把上傳的圖片讀取出來

    在各大網(wǎng)站上都可以實現(xiàn)上傳頭像功能,可以選擇自己喜歡的圖片做頭像,從本地上傳,今天小編給大家分享Java實現(xiàn)圖片上傳到服務器并把上傳的圖片讀取出來,需要的朋友參考下
    2017-02-02
  • 詳解SpringBoot?調用外部接口的三種方式

    詳解SpringBoot?調用外部接口的三種方式

    SpringBoot不僅繼承了Spring框架原有的優(yōu)秀特性,而且還通過簡化配置來進一步簡化了Spring應用的整個搭建和開發(fā)過程,這篇文章主要介紹了SpringBoot?調用外部接口的三種方式,需要的朋友可以參考下
    2023-04-04
  • Java精品項目瑞吉外賣之登陸的完善與退出功能篇

    Java精品項目瑞吉外賣之登陸的完善與退出功能篇

    這篇文章主要為大家詳細介紹了java精品項目-瑞吉外賣訂餐系統(tǒng),此項目過大,分為多章獨立講解,本篇內容為新增菜品和分頁查詢功能的實現(xiàn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • java稀疏數(shù)組的示例代碼

    java稀疏數(shù)組的示例代碼

    這篇文章主要介紹了java稀疏數(shù)組,稀疏數(shù)組,記錄一共有幾行幾列,有多少個不同值,把具有不同值的元素和行里了及值記錄在一個小規(guī)模的數(shù)組中,從而縮小程序的規(guī)模,對java稀疏數(shù)組相關知識感興趣的朋友一起看看吧
    2022-07-07
  • 使用IDEA如何將本地代碼上傳到GitCode

    使用IDEA如何將本地代碼上傳到GitCode

    文章主要介紹了使用GitCode進行代碼倉庫管理的步驟,包括注冊、創(chuàng)建倉庫、IDEA創(chuàng)建本地倉庫、設置遠程倉庫、配置賬號密碼和進行代碼推送等操作,文章強調使用CSDN賬號同步注冊,并使用個人訪問令牌進行操作,最后完成代碼的推送
    2026-04-04
  • 詳解如何在SpringBoot中自定義參數(shù)解析器

    詳解如何在SpringBoot中自定義參數(shù)解析器

    這篇文章主要為大家詳細介紹了如何在SpringBoot中實現(xiàn)自定義參數(shù)解析器,文中的示例代碼講解詳細,對我們學習或工作有一定幫助,需要的可以參考一下
    2022-05-05
  • Eureka源碼閱讀之環(huán)境搭建及工程結構

    Eureka源碼閱讀之環(huán)境搭建及工程結構

    這篇文章主要為大家介紹了Eureka源碼閱讀之環(huán)境搭建的工程結構及調試需知詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>
    2022-10-10
  • Spring?Security放行的接口Knife4j靜態(tài)資源的問題小結

    Spring?Security放行的接口Knife4j靜態(tài)資源的問題小結

    這篇文章主要介紹了Spring?Security使用Knife4j靜態(tài)資源的問題小結,項目中使用?Spring?Security?做身份認證和授權,使用?Knife4j?做接口調試,需要?Spring?Security?放行的接口記錄在?RequestMatcherConstant?類中,感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • SpringBoot封裝響應數(shù)據(jù)實現(xiàn)過程詳解

    SpringBoot封裝響應數(shù)據(jù)實現(xiàn)過程詳解

    這篇文章主要介紹了SpringBoot封裝響應數(shù)據(jù)實現(xiàn)過程,SpringBoot響應數(shù)據(jù)封裝是指在SpringBoot應用程序中,將返回的數(shù)據(jù)進行封裝,以便于前端頁面或其他客戶端使用,感興趣想要詳細了解可以參考下文
    2023-05-05
  • Java雜談之合格程序員一定要會閱讀別人的源碼

    Java雜談之合格程序員一定要會閱讀別人的源碼

    閱讀別人的代碼作為開發(fā)人員是一件經常要做的事情。一個是學習新的編程語言的時候通過閱讀別人的代碼是一個最好的學習方法,另外是積累編程經驗
    2021-09-09

最新評論

白山市| 涞水县| 庐江县| 铁力市| 钟山县| 开平市| 胶州市| 汕尾市| 新丰县| 铜鼓县| 宜昌市| 马鞍山市| 兴安县| 青州市| 大城县| 富平县| 巫山县| 南通市| 图们市| 大兴区| 陕西省| 红安县| 西青区| 武冈市| 安新县| 微山县| 容城县| 湖北省| 军事| 滕州市| 清徐县| 登封市| 麻栗坡县| 龙口市| 张家川| 庆云县| 九龙县| 木里| 庐江县| 湖南省| 白玉县|