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

Springboot使用Rabbitmq的延時(shí)隊(duì)列+死信隊(duì)列實(shí)現(xiàn)消息延期消費(fèi)

 更新時(shí)間:2025年01月08日 10:04:48   作者:WalkerShen  
本文介紹了RabbitMQ的延時(shí)隊(duì)列和死信隊(duì)列,解釋了它們的工作原理及其應(yīng)用場(chǎng)景,延時(shí)隊(duì)列允許消息在設(shè)定的時(shí)間后被消費(fèi),結(jié)合實(shí)際案例,展示了如何實(shí)現(xiàn)和使用延時(shí)隊(duì)列和死信隊(duì)列,感興趣的朋友一起看看吧

簡(jiǎn)介

RabbitMQ 的延時(shí)隊(duì)列(Delayed Queue)是指消息在發(fā)送到隊(duì)列后,會(huì)在一定的時(shí)間內(nèi)被延遲處理,直到預(yù)設(shè)的延遲時(shí)間結(jié)束,消息才會(huì)被消費(fèi)者消費(fèi)。RabbitMQ 本身并不原生支持延時(shí)隊(duì)列,但我們可以通過(guò)一些插件或特定配置來(lái)實(shí)現(xiàn)這種功能。

延時(shí)隊(duì)列的應(yīng)用場(chǎng)景

  • 定時(shí)任務(wù):比如定時(shí)發(fā)送郵件、推送通知等操作。
  • 重試機(jī)制:當(dāng)某些任務(wù)失敗時(shí),可以讓任務(wù)在一段時(shí)間后再次嘗試。
  • 延遲消費(fèi):在特定時(shí)間后消費(fèi)消息,而不是立即消費(fèi)。

死信隊(duì)列(Dead Letter Queue,簡(jiǎn)稱 DLQ)是消息隊(duì)列中的一個(gè)特殊隊(duì)列,用于存放那些因某些原因無(wú)法被正常消費(fèi)的消息。死信隊(duì)列在許多消息隊(duì)列系統(tǒng)(如 RabbitMQ、Kafka 等)中都有應(yīng)用。通過(guò)將無(wú)法消費(fèi)的消息轉(zhuǎn)移到死信隊(duì)列中,可以幫助開(kāi)發(fā)者發(fā)現(xiàn)和處理消息消費(fèi)過(guò)程中的異?;蝈e(cuò)誤。

死信隊(duì)列的主要用途是:

  • 錯(cuò)誤處理:用于捕獲無(wú)法消費(fèi)的消息,避免這些消息丟失,并提供后續(xù)人工干預(yù)或自動(dòng)重試的機(jī)會(huì)。
  • 監(jiān)控和診斷:通過(guò)查看死信隊(duì)列,可以幫助開(kāi)發(fā)者快速發(fā)現(xiàn)問(wèn)題,例如隊(duì)列被溢出、消息格式不正確等。
  • 防止數(shù)據(jù)丟失:將那些因?yàn)槌瑫r(shí)、隊(duì)列溢出、消費(fèi)失敗等原因無(wú)法處理的消息放入死信隊(duì)列,可以保證它們不會(huì)丟失,后續(xù)可以進(jìn)一步調(diào)查和處理。

本文結(jié)合延時(shí)隊(duì)列和死信隊(duì)列,延時(shí)隊(duì)列的消息設(shè)置過(guò)期時(shí)間,在時(shí)間過(guò)期之后,將消息內(nèi)容推送到死信隊(duì)列中進(jìn)行處理。

整合邏輯

依賴

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.27</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
            <version>2.7.7</version>
        </dependency>

配置

server:
  port: 8081
spring:
  application:
    name: walker-rabbitmq
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest_walker
    password: guest

創(chuàng)建交換機(jī)|隊(duì)列

延時(shí)隊(duì)列

package com.walker.rabbitmq.delay.config;
import com.walker.rabbitmq.delay.constants.BaseConstant;
import com.walker.rabbitmq.delay.enums.RabbitMqConfigEnum;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class OrderDelayRabbitConfig {
//    交換機(jī)
    @Bean
    public DirectExchange orderDelayExchange(){
        return new DirectExchange(RabbitMqConfigEnum.ORDER_DELAY.getExchange());
    }
//    隊(duì)列
    @Bean
    public Queue orderDelayQueue(){
        Map<String,Object> args = new HashMap<>();
//        延時(shí)隊(duì)列,需要綁定死信隊(duì)列,在ttl到期之后,將隊(duì)列轉(zhuǎn)到死信隊(duì)列
        args.put(BaseConstant.xDeadLetterExchange,RabbitMqConfigEnum.ORDER_DEAD.getExchange());
        args.put(BaseConstant.xDeadLetterRoutingKey,RabbitMqConfigEnum.ORDER_DEAD.getRoutingKey());
        return QueueBuilder.durable(RabbitMqConfigEnum.ORDER_DELAY.getQueue()).autoDelete().withArguments(args).build();
    }
//
    @Bean
    public Binding orderDelayQueueBinding(){
        return BindingBuilder.bind(orderDelayQueue()).to(orderDelayExchange()).with(RabbitMqConfigEnum.ORDER_DELAY.getRoutingKey());
    }
}

死信隊(duì)列

package com.walker.rabbitmq.delay.config;
import com.walker.rabbitmq.delay.enums.RabbitMqConfigEnum;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OrderDeadRabbitConfig {
//    交換機(jī)
    @Bean
    public DirectExchange orderDeadExchange(){
        return new DirectExchange(RabbitMqConfigEnum.ORDER_DEAD.getExchange());
    }
//    隊(duì)列
    @Bean
    public Queue orderDeadQueue(){
        return QueueBuilder.durable(RabbitMqConfigEnum.ORDER_DEAD.getQueue()).autoDelete().build();
    }
//   交換機(jī)、隊(duì)列、路由鍵綁定
    @Bean
    public Binding orderDeadQueueBinding(){
        return BindingBuilder.bind(orderDeadQueue()).to(orderDeadExchange())
                .with(RabbitMqConfigEnum.ORDER_DEAD.getRoutingKey());
    }
}

常量

package com.walker.rabbitmq.delay.constants;
import com.walker.rabbitmq.delay.enums.RabbitMqConfigEnum;
public interface BaseConstant {
    String xDeadLetterExchange = "x-dead-letter-exchange";
    String xDeadLetterRoutingKey = "x-dead-letter-routing-key";
}

相關(guān)枚舉

package com.walker.rabbitmq.delay.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum RabbitMqConfigEnum {
    ORDER_DELAY("direct","訂單延時(shí)隊(duì)列","order_delay_exchange", "order_delay_queue", "order_delay_routing_key",true),
    ORDER_DEAD("direct","訂單死信隊(duì)列","order_dead_exchange", "order_dead_queue", "order_dead_routing_key",true);
    private final String type;
    private final String title;
    private final String exchange;
    private final String queue;
    private final String routingKey;
    private final Boolean durable;
}

rabbitmq工具類封裝

package com.walker.rabbitmq.delay.service;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.json.JSONUtil;
import com.rabbitmq.client.Channel;
import com.walker.rabbitmq.delay.enums.RabbitMqConfigEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.function.Consumer;
import java.util.function.Function;
@Component
@Slf4j
public class RabbitmqService {
    @Resource
    private RabbitTemplate rabbitTemplate;
    /**
    * author:walker
    * time: 2024/12/30
    * description:  無(wú)返回結(jié)果的手動(dòng)處理方式
    */
    public void doWithManualAck(String event, Message message, Channel channel, Consumer<String> method) {
        String data = new String(message.getBody());
        try {
            method.accept(data);
            sendAck(message, channel);
        } catch (Exception e) {
            log.error("處理事件[{}]異常數(shù)據(jù)為:{},原因如下:",event,data, e);
            sendNack(message, channel);
        }
    }
    /**
     * author:walker
     * time: 2024/12/30
     * description:  根據(jù)返回的布爾類型,進(jìn)行確認(rèn)和拒絕
     */
    public void doWithManualAck(String event, Message message, Channel channel, Function<String,Boolean> method) {
        String data = new String(message.getBody());
        try {
            Boolean res = method.apply(data);
            if(BooleanUtil.isTrue(res)){
                sendAck(message, channel);
            }else{
                sendNack(message, channel);
            }
        } catch (Exception e) {
            log.error("處理事件[{}]異常數(shù)據(jù)為:{},原因如下:",event,data, e);
            sendNack(message, channel);
        }
    }
    //    確認(rèn)消息
    public void sendAck(Message message, Channel channel) throws IOException {
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
    //    拒絕消息
    public void sendNack(Message message, Channel channel) {
        try {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        } catch (IOException e) {
            log.error("消息消費(fèi)失敗,消息ID:{}", message.getMessageProperties().getMessageId(), e);
        }
    }
    public <T> void sendDelayMsg(RabbitMqConfigEnum configEnum, T data, Integer delayTime) {
        rabbitTemplate.convertAndSend(configEnum.getExchange(), configEnum.getRoutingKey(),
                JSONUtil.toJsonStr(data), new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setExpiration(String.valueOf(delayTime));
                        return message;
                    }
                });
    }
}

案例

實(shí)體類

package com.walker.rabbitmq.delay.entity;
import lombok.Data;
@Data
public class OrderInfo {
    private String productName;
    private Integer num;
    private String userName;
    private String orderTime;
}

controller 創(chuàng)建訂單

package com.walker.rabbitmq.delay.controller;
import com.walker.rabbitmq.delay.enums.RabbitMqConfigEnum;
import com.walker.rabbitmq.delay.entity.OrderInfo;
import com.walker.rabbitmq.delay.service.RabbitmqService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Date;
@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {
    @Resource
    private RabbitmqService rabbitmqService;
    /**
    * author:walker
    * time: 2025/1/2
    * description:  下單
    */
    @GetMapping("/create")
    public void createOrder() {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setProductName("羽毛球");
        orderInfo.setUserName("張三");
        orderInfo.setOrderTime("2025-01-02 12:00:00");
        orderInfo.setNum(1);
        log.info("發(fā)送消息時(shí)間{}",new Date());
        rabbitmqService.sendDelayMsg(RabbitMqConfigEnum.ORDER_DELAY,orderInfo,10000);
    }
}

消費(fèi)者監(jiān)聽(tīng)消息

消費(fèi)者接口

package com.walker.rabbitmq.delay.service;
public interface IRabbitCosumerHandler {
    Boolean handle(String message);
}

消費(fèi)者監(jiān)聽(tīng)方法

package com.walker.rabbitmq.delay.listener;
import com.rabbitmq.client.Channel;
import com.walker.rabbitmq.delay.enums.RabbitMqConfigEnum;
import com.walker.rabbitmq.delay.constants.BaseConstant;
import com.walker.rabbitmq.delay.service.IRabbitCosumerHandler;
import com.walker.rabbitmq.delay.service.RabbitmqService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
@Slf4j
@Component
public class OrderDeadLetterQueueConsumer implements IRabbitCosumerHandler {
    @Resource
    private RabbitmqService rabbitmqService;
    @RabbitListener(queues = "#{T(com.walker.rabbitmq.delay.enums.RabbitMqConfigEnum).ORDER_DEAD.getQueue()}",ackMode = "MANUAL")
    public void receive(Message message, Channel channel) throws IOException {
        log.info("接受消息時(shí)間 {}",new Date());
        String msg = new String(message.getBody());
        log.info("當(dāng)前時(shí)間:{},隊(duì)列{}收到消息:{}", new Date().toString(),RabbitMqConfigEnum.ORDER_DEAD.getQueue(), msg);
        rabbitmqService.doWithManualAck(RabbitMqConfigEnum.ORDER_DEAD.getTitle(), message, channel, this::handle);
    }
    @Override
    public Boolean handle(String message) {
//        處理邏輯
        log.info("進(jìn)行訂單取消的操作");
        return true;
    }
}

到此這篇關(guān)于Springboot使用Rabbitmq的延時(shí)隊(duì)列+死信隊(duì)列實(shí)現(xiàn)消息延期消費(fèi) 的文章就介紹到這了,更多相關(guān)Springboot使用Rabbitmq消息延期消費(fèi) 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中==符號(hào)與equals()的使用詳解(測(cè)試兩個(gè)變量是否相等)

    Java中==符號(hào)與equals()的使用詳解(測(cè)試兩個(gè)變量是否相等)

    下面小編就為大家?guī)?lái)一篇Java中==符號(hào)與equals()的使用詳解(測(cè)試兩個(gè)變量是否相等)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • IntelliJ IDEA 中g(shù)it的使用圖文教程

    IntelliJ IDEA 中g(shù)it的使用圖文教程

    本文通過(guò)圖文并茂的形式給大家介紹了IntelliJ IDEA 中g(shù)it的使用,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2018-02-02
  • Java中的FutureTask用法和原理解析

    Java中的FutureTask用法和原理解析

    本文深入剖析了Java并發(fā)編程中的FutureTask,包括其與Callable和Future的關(guān)系、使用方法以及內(nèi)部實(shí)現(xiàn)原理,FutureTask是Future的基礎(chǔ)實(shí)現(xiàn),用于處理異步計(jì)算結(jié)果,提供了任務(wù)執(zhí)行結(jié)果獲取和任務(wù)取消等方法
    2024-10-10
  • Java 并發(fā)編程之ThreadLocal詳解及實(shí)例

    Java 并發(fā)編程之ThreadLocal詳解及實(shí)例

    這篇文章主要介紹了Java 并發(fā)編程之ThreadLocal詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Spring中的事務(wù)傳播行為示例詳解

    Spring中的事務(wù)傳播行為示例詳解

    這篇文章主要給大家介紹了關(guān)于Spring中事務(wù)傳播行為的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Java的List集合框架之LinkedList詳細(xì)解析

    Java的List集合框架之LinkedList詳細(xì)解析

    這篇文章主要介紹了Java的List集合框架之LinkedList詳細(xì)解析,LinkedList底層是內(nèi)部Node類的存儲(chǔ),prev、next、item值,同時(shí)最外層還有first、last節(jié)點(diǎn),需要的朋友可以參考下
    2023-11-11
  • java語(yǔ)言描述Redis分布式鎖的正確實(shí)現(xiàn)方式

    java語(yǔ)言描述Redis分布式鎖的正確實(shí)現(xiàn)方式

    這篇文章主要介紹了java語(yǔ)言描述Redis分布式鎖的正確實(shí)現(xiàn)方式,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • java web個(gè)人通訊錄系統(tǒng)設(shè)計(jì)

    java web個(gè)人通訊錄系統(tǒng)設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了java web個(gè)人通訊錄系統(tǒng)設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • SpringBoot項(xiàng)目攔截器獲取Post方法的請(qǐng)求body實(shí)現(xiàn)

    SpringBoot項(xiàng)目攔截器獲取Post方法的請(qǐng)求body實(shí)現(xiàn)

    本文主要介紹了SpringBoot項(xiàng)目攔截器獲取Post方法的請(qǐng)求body,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java中的顯示鎖ReentrantLock使用與原理詳解

    Java中的顯示鎖ReentrantLock使用與原理詳解

    這篇文章主要介紹了Java中的顯示鎖ReentrantLock使用與原理詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11

最新評(píng)論

防城港市| 嘉荫县| 深州市| 铁力市| 三原县| 闵行区| 尚义县| 长阳| 三原县| 琼结县| 余庆县| 华容县| 阜新市| 东安县| 晋州市| 威宁| 民县| 眉山市| 茌平县| 大邑县| 赤城县| 凉城县| 汽车| 云浮市| 安康市| 疏附县| 兰溪市| 漳平市| 天台县| 吉林省| 韶关市| 苏尼特右旗| 阿城市| 和林格尔县| 南部县| 明水县| 毕节市| 淮滨县| 武安市| 鲁甸县| 崇文区|