1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        SpringBoot集成Redisson實(shí)現(xiàn)延遲隊(duì)列

        共 9370字,需瀏覽 19分鐘

         ·

        2021-04-27 16:15

        點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

        優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

        使用場(chǎng)景

        1、下單成功,30分鐘未支付。支付超時(shí),自動(dòng)取消訂單


        2、訂單簽收,簽收后7天未進(jìn)行評(píng)價(jià)。訂單超時(shí)未評(píng)價(jià),系統(tǒng)默認(rèn)好評(píng)


        3、下單成功,商家5分鐘未接單,訂單取消


        4、配送超時(shí),推送短信提醒


        ......


        對(duì)于延時(shí)比較長(zhǎng)的場(chǎng)景、實(shí)時(shí)性不高的場(chǎng)景,我們可以采用任務(wù)調(diào)度的方式定時(shí)輪詢處理。如:xxl-job


        今天我們采用一種比較簡(jiǎn)單、輕量級(jí)的方式,使用 Redis 的延遲隊(duì)列來進(jìn)行處理。當(dāng)然有更好的解決方案,可根據(jù)公司的技術(shù)選型和業(yè)務(wù)體系選擇最優(yōu)方案。如:使用消息中間件Kafka、RabbitMQ 的延遲隊(duì)列


        先不討論其實(shí)現(xiàn)原理,直接實(shí)戰(zhàn)上代碼先實(shí)現(xiàn)基于 Redis 的延遲隊(duì)列


        1、引入 Redisson 依賴

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.10.5</version>
        </dependency>

        2、Nacos 配置 Redis 連接

        spring:
          redis:
            host: 127.0.0.1
            port: 6379
            password: 123456
            database: 12
            timeout: 3000

        3、創(chuàng)建 RedissonConfig 配置

        /**
         * Created by LPB on 2020/04/20.
         */
        @Configuration
        public class RedissonConfig {
         
         @Value("${spring.redis.host}")
         private String host;
         @Value("${spring.redis.port}")
         private int port;
         @Value("${spring.redis.database}")
         private int database;
         @Value("${spring.redis.password}")
         private String password;
         
         @Bean
         public RedissonClient redissonClient() {
          Config config = new Config();
          config.useSingleServer()
           .setAddress("redis://" + host + ":" + port)
           .setDatabase(database)
           .setPassword(password);
          return Redisson.create(config);
         }
         
        }

        4、封裝 Redis 延遲隊(duì)列工具類

        /**
         * redis延遲隊(duì)列工具
         * Created by LPB on 2021/04/20.
         */
        @Slf4j
        @Component
        public class RedisDelayQueueUtil {
         
            @Autowired
         private RedissonClient redissonClient;
         
            /**
             * 添加延遲隊(duì)列
             * @param value 隊(duì)列值
             * @param delay 延遲時(shí)間
             * @param timeUnit 時(shí)間單位
             * @param queueCode 隊(duì)列鍵
             * @param <T>
             */
            public <T> void addDelayQueue(T value, long delay, TimeUnit timeUnit, String queueCode){
                try {
                    RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque(queueCode);
                    RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
                    delayedQueue.offer(value, delay, timeUnit);
           log.info("(添加延時(shí)隊(duì)列成功) 隊(duì)列鍵:{},隊(duì)列值:{},延遲時(shí)間:{}", queueCode, value, timeUnit.toSeconds(delay) + "秒");
                } catch (Exception e) {
                    log.error("(添加延時(shí)隊(duì)列失敗) {}", e.getMessage());
                    throw new RuntimeException("(添加延時(shí)隊(duì)列失敗)");
                }
            }
         
         /**
          * 獲取延遲隊(duì)列
          * @param queueCode
          * @param <T>
          * @return
          * @throws InterruptedException
          */
            public <T> T getDelayQueue(String queueCode) throws InterruptedException {
                RBlockingDeque<Map> blockingDeque = redissonClient.getBlockingDeque(queueCode);
                T value  = (T) blockingDeque.take();
                return value;
         }
        }

        5、創(chuàng)建延遲隊(duì)列業(yè)務(wù)枚舉

        /**
         * 延遲隊(duì)列業(yè)務(wù)枚舉
         * Created by LPB on 2021/04/20.
         */
        @Getter
        @NoArgsConstructor
        @AllArgsConstructor
        public enum RedisDelayQueueEnum {
         
         ORDER_PAYMENT_TIMEOUT("ORDER_PAYMENT_TIMEOUT","訂單支付超時(shí),自動(dòng)取消訂單""orderPaymentTimeout"),
         ORDER_TIMEOUT_NOT_EVALUATED("ORDER_TIMEOUT_NOT_EVALUATED""訂單超時(shí)未評(píng)價(jià),系統(tǒng)默認(rèn)好評(píng)""orderTimeoutNotEvaluated");
         
         /**
          * 延遲隊(duì)列 Redis Key
          */
         private String code;
         
         /**
          * 中文描述
          */
         private String name;
         
         /**
          * 延遲隊(duì)列具體業(yè)務(wù)實(shí)現(xiàn)的 Bean
          * 可通過 Spring 的上下文獲取
          */
         private String beanId;
         
        }

        6、定義延遲隊(duì)列執(zhí)行器

        /**
         * 延遲隊(duì)列執(zhí)行器
         * Created by LPB on 2021/04/20.
         */
        public interface RedisDelayQueueHandle<T> {
         
         void execute(T t);
         
        }

        7、創(chuàng)建枚舉中定義的Bean,并實(shí)現(xiàn)延遲隊(duì)列執(zhí)行器

        • OrderPaymentTimeout:訂單支付超時(shí)延遲隊(duì)列處理類

        /**
         * 訂單支付超時(shí)處理類
         * Created by LPB on 2021/04/20.
         */
        @Component
        @Slf4j
        public class OrderPaymentTimeout implements RedisDelayQueueHandle<Map> {
         @Override
         public void execute(Map map) {
          log.info("(收到訂單支付超時(shí)延遲消息) {}", map);
          // TODO 訂單支付超時(shí),自動(dòng)取消訂單處理業(yè)務(wù)...
         
         }
        }
        • OrderTimeoutNotEvaluated:訂單超時(shí)未評(píng)價(jià)延遲隊(duì)列處理類

        /**
         * 訂單超時(shí)未評(píng)價(jià)處理類
         * Created by LPB on 2021/04/20.
         */
        @Component
        @Slf4j
        public class OrderTimeoutNotEvaluated implements RedisDelayQueueHandle<Map> {
         @Override
         public void execute(Map map) {
          log.info("(收到訂單超時(shí)未評(píng)價(jià)延遲消息) {}", map);
          // TODO 訂單超時(shí)未評(píng)價(jià),系統(tǒng)默認(rèn)好評(píng)處理業(yè)務(wù)...
         
         }
        }

        8、創(chuàng)建延遲隊(duì)列消費(fèi)線程,項(xiàng)目啟動(dòng)完成后開啟

        /**
         * 啟動(dòng)延遲隊(duì)列
         * Created by LPB on 2021/04/20.
         */
        @Slf4j
        @Component
        public class RedisDelayQueueRunner implements CommandLineRunner {
         
         @Autowired
         private RedisDelayQueueUtil redisDelayQueueUtil;
         
         @Override
         public void run(String... args) {
          new Thread(() -> {
           while (true){
            try {
             RedisDelayQueueEnum[] queueEnums = RedisDelayQueueEnum.values();
             for (RedisDelayQueueEnum queueEnum : queueEnums) {
              Object value = redisDelayQueueUtil.getDelayQueue(queueEnum.getCode());
              if (value != null) {
               RedisDelayQueueHandle redisDelayQueueHandle = SpringUtil.getBean(queueEnum.getBeanId());
               redisDelayQueueHandle.execute(value);
              }
             }
            } catch (InterruptedException e) {
             log.error("(Redis延遲隊(duì)列異常中斷) {}", e.getMessage());
            }
           }
          }).start();
          log.info("(Redis延遲隊(duì)列啟動(dòng)成功)");
         }
        }

        以上步驟,Redis 延遲隊(duì)列核心代碼已經(jīng)完成,下面我們寫一個(gè)測(cè)試接口,用 PostMan 模擬測(cè)試一下


        9、創(chuàng)建一個(gè)測(cè)試接口,模擬添加延遲隊(duì)列

        /**
         * 延遲隊(duì)列測(cè)試
         * Created by LPB on 2020/04/20.
         */
        @RestController
        public class RedisDelayQueueController {
         
         @Autowired
         private RedisDelayQueueUtil redisDelayQueueUtil;
         
         @PostMapping("/addQueue")
         public void addQueue() {
          Map<String, String> map1 = new HashMap<>();
          map1.put("orderId""100");
          map1.put("remark""訂單支付超時(shí),自動(dòng)取消訂單");
         
          Map<String, String> map2 = new HashMap<>();
          map2.put("orderId""200");
          map2.put("remark""訂單超時(shí)未評(píng)價(jià),系統(tǒng)默認(rèn)好評(píng)");
         
          // 添加訂單支付超時(shí),自動(dòng)取消訂單延遲隊(duì)列。為了測(cè)試效果,延遲10秒鐘
          redisDelayQueueUtil.addDelayQueue(map1, 10, TimeUnit.SECONDS, RedisDelayQueueEnum.ORDER_PAYMENT_TIMEOUT.getCode());
         
          // 訂單超時(shí)未評(píng)價(jià),系統(tǒng)默認(rèn)好評(píng)。為了測(cè)試效果,延遲20秒鐘
          redisDelayQueueUtil.addDelayQueue(map2, 20, TimeUnit.SECONDS, RedisDelayQueueEnum.ORDER_TIMEOUT_NOT_EVALUATED.getCode());
         }
         
        }

        10、啟動(dòng) SpringBoot 項(xiàng)目,用 PostMan 調(diào)用接口添加延遲隊(duì)列

        • 通過 Redis 客戶端可看到兩個(gè)延遲隊(duì)列已添加成功


        • 查看 IDEA 控制臺(tái)日志可看到延遲隊(duì)列已消費(fèi)成功


         

        ————————————————

        版權(quán)聲明:本文為CSDN博主「KK·Liu先生」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。

        原文鏈接:

        https://blog.csdn.net/qq_40087415/article/details/115940092





        粉絲福利:Java從入門到入土學(xué)習(xí)路線圖

        ??????

        ??長(zhǎng)按上方微信二維碼 2 秒


        感謝點(diǎn)贊支持下哈 

        瀏覽 143
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲AV成人影视网 | 涩涩资源网 | 大香蕉综合视频 | 少妇一级淫片免费放在线 | 亚洲乱伦小说图片 | 边吃奶边操| 人人婷人人操 | 亚洲自拍小视频 | 久热青草 | 久热精品视频在线 |