点击上方[全栈开发者社区]右上角[...][设为星标⭐

点击领取全栈资料:全栈资料

目前常见的应用软件都有消息的延迟推送的影子,应用也极为广泛,例如:

  • 淘宝七天自动确认收货。在我们签收商品后,物流系统会在七天后延时发送一个消息给支付系统,通知支付系统将款打给商家,这个过程持续七天,就是使用了消息中间件的延迟推送功能;

  • 12306 购票支付确认页面。我们在选好票点击确定跳转的页面中往往都会有倒计时,代表着 30 分钟内订单不确认的话将会自动取消订单。其实在下订单那一刻开始购票业务系统就会发送一个延时消息给订单系统,延时 30 分钟,告诉订单系统订单未完成,如果我们在 30 分钟内完成了订单,则可以通过逻辑代码判断来忽略掉收到的消息。

在上面两种场景中,如果我们使用下面两种传统解决方案无疑大大降低了系统的整体性能和吞吐量:

  • 使用 Redis 给订单设置过期时间,最后通过判断 Redis 中是否还有该订单来决定订单是否已经完成。这种解决方案相较于消息的延迟推送性能较低,因为我们知道 Redis 都是存储于内存中,我们遇到恶意下单或者刷单的将会给内存带来巨大压力;

  • 使用传统的数据库轮询来判断数据库表中订单的状态,这无疑增加了 IO 次数,性能极低;

  • 使用 JVM 原生的 DelayQueue ,也是大量占用内存,而且没有持久化策略,系统宕机或者重启都会丢失订单信息。

消息延迟推送的实现

在 RabbitMQ 3.6.x 之前我们一般采用信队列 + TTL过期时间来实现延迟队列,我们这里不做过多介绍。

在 RabbitMQ 3.6.x 开始,RabbitMQ 官方提供了延迟队列的插件,可以下载放置到 RabbitMQ 根目录下的 plugins 下。

插件下载地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange

首先,我们创建交换机和消息队列。

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 MQConfig {public static final String LAZY_EXCHANGE = "Ex.LazyExchange";public static final String LAZY_QUEUE = "MQ.LazyQueue";public static final String LAZY_KEY = "lazy.#";@Beanpublic TopicExchange lazyExchange() {//Map<String, Object> pros = new HashMap<>();//设置交换机支持延迟消息推送//pros.put("x-delayed-message", "topic");TopicExchange exchange = new TopicExchange(LAZY_EXCHANGE, true, false, pros);exchange.setDelayed(true);return exchange;}@Beanpublic Queue lazyQueue() {return new Queue(LAZY_QUEUE, true);}@Beanpublic Binding lazyBinding() {return BindingBuilder.bind(lazyQueue()).to(lazyExchange()).with(LAZY_KEY);}
}

我们在 Exchange 的声明中可以设置 exchange.setDelayed(true) 来开启延迟队列,也可以设置为以下内容传入交换机声明的方法中,因为第一种方式的底层就是通过这种方式来实现的。

//Map<String, Object> pros = new HashMap<>();
//设置交换机支持延迟消息推送
//pros.put("x-delayed-message", "topic");
TopicExchange exchange = new TopicExchange(LAZY_EXCHANGE, true, false, pros);

发送消息时我们需要指定延迟推送的时间,我们这里在发送消息的方法中传入参数 new MessagePostProcessor() 是为了获得 Message对象,因为需要借助 Message对象的API 来设置延迟时间。

import com.anqi.mq.config.MQConfig;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Date;@Component
public class MQSender {@Autowiredprivate RabbitTemplate rabbitTemplate;//confirmCallback returnCallback 代码省略,请参照上一篇public void sendLazy(Object message) {rabbitTemplate.setMandatory(true);rabbitTemplate.setConfirmCallback(confirmCallback);rabbitTemplate.setReturnCallback(returnCallback);//id + 时间戳 全局唯一CorrelationData correlationData = new CorrelationData("12345678909" + new Date());//发送消息时指定 header 延迟时间rabbitTemplate.convertAndSend(MQConfig.LAZY_EXCHANGE, "lazy.boot", message,new MessagePostProcessor() {@Overridepublic Message postProcessMessage(Message message) throws AmqpException {//设置消息持久化message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);//message.getMessageProperties().setHeader("x-delay", "6000");message.getMessageProperties().setDelay(6000);return message;}}, correlationData);}
}

我们可以观察 setDelay(Integer i) 底层代码,也是在 header 中设置 x-delay。等同于我们手动设置 header

message.getMessageProperties().setHeader("x-delay", "6000");
/*** Set the x-delay header.* @param delay the delay.* @since 1.6*/
public void setDelay(Integer delay) {if (delay == null || delay < 0) {this.headers.remove(X_DELAY);} else {this.headers.put(X_DELAY, delay);}
}

消费端进行消费:

import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.util.Map;@Component
public class MQReceiver {@RabbitListener(queues = "MQ.LazyQueue")@RabbitHandlerpublic void onLazyMessage(Message msg, Channel channel) throws IOException {long deliveryTag = msg.getMessageProperties().getDeliveryTag();channel.basicAck(deliveryTag, true);System.out.println("lazy receive " + new String(msg.getBody()));}
}

测试结果

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;@SpringBootTest
@RunWith(SpringRunner.class)
public class MQSenderTest {@Autowiredprivate MQSender mqSender;@Testpublic void sendLazy() throws Exception {String msg = "hello spring boot";mqSender.sendLazy(msg + ":");}
}

果然在 6 秒后收到了消息 “lazy receive hello spring boot:”。

转自:海向,

链接:cnblogs.com/haixiang/p/10966985.html

觉得本文对你有帮助?请分享给更多人关注「全栈开发者社区」加星标,提升全栈技能
本公众号会不定期给大家发福利,包括送书、学习资源等,敬请期待吧!
如果感觉推送内容不错,不妨右下角点个在看转发朋友圈或收藏,感谢支持。
好文章,留言、点赞、在看和分享一条龙吧❤️

淘宝七天自动确认收货,让你设计,可以怎么实现?(附源码)相关推荐

  1. 从零开发短视频电商 30分钟未支付订单自动关闭、七天自动确认收货等延迟任务问题

    文章目录 常见延迟任务 常见解决方案 主动形式 被动形式 基于Redis实现ZSet的方式.键空间通知的方式 ZSet的方式 键空间通知的方式 RocketMQ延迟消息 延迟消息级别配置 客户端发送延 ...

  2. 艾司博讯:拼多多没确认收货多久系统才自动确认收货

    现在大多朋友对网购都不陌生,一般我们收到货后都会确认收货,然后给商品进行评价.当然,一些朋友比较忙或者没有确认收货的习惯,过了一段时间后会自动确认收货.那么拼多多确认收货期限是几天,下面就为大家带来介 ...

  3. php怎么点击确认收货,解决修正Ecshop的recieve.php邮件自动确认收货问题

    解决修正Ecshop的recieve.php邮件自动确认收货问题 将之前的ecshop确认收货页面改成如下格式: //确认页面 $act = !empty($_REQUEST['act']) ? ra ...

  4. php 自动收货’_PHP实现电商订单自动确认收货redis队列

    一.场景 之前做的电商平台,用户在收到货之后,大部分都不会主动的点击确认收货,导致给商家结款的时候,商家各种投诉,于是就根据需求,要做一个订单在发货之后的x天自动确认收货.所谓的订单自动确认收货,就是 ...

  5. PHP与redis队列实现电商订单自动确认收货

    一.场景 之前做的电商平台,用户在收到货之后,大部分都不会主动的点击确认收货,导致给商家结款的时候,商家各种投诉,于是就根据需求,要做一个订单在发货之后的x天自动确认收货.所谓的订单自动确认收货,就是 ...

  6. php自动收货,如何在PHP中实现一个订单自动确认收货的redis队列

    如何在PHP中实现一个订单自动确认收货的redis队列 发布时间:2020-12-14 15:45:55 来源:亿速云 阅读:65 作者:Leah 本篇文章为大家展示了如何在PHP中实现一个订单自动确 ...

  7. 拼多多自动确认收货后还能退吗?退货申请期限是多久?

    其实,在确认收货一点也不难,只需要签收后,点击确认收货按钮就行了.不过,还是有不少伙伴都了懒于去点击确认收货,这个时候系统会自动确认收货 拼多多自动确认收货后还能退吗? 1.常规商品15天内是消费者收 ...

  8. php 10天自动确认收货,ECSHOP修正recieve.php判断不严谨导致邮件自动确认收货

    今天小编在一个技术论坛上看了这样一个求助帖,一位用ecshop建站的店长朋友反应"用户明明没有确认收货,可是会员管理里面,订单状态却显示为已经确认收货".看到这个求助帖之后,小编很 ...

  9. php 10天自动确认收货,修正Ecshop的recieve.php邮件自动确认收货BUG

    Ecshop没有点击邮件中的确认收货链接,但是进入个人中心却发现订单状态已经更改为了已经收到货的状态了.问题出在QQ邮箱.Ecshop的recieve设计是用户点了链接直接就改变订单状态到确认收货,而 ...

  10. php怎么点击确认收货,Ecshop的recieve.php邮件自动确认收货BUG如何修正

    今天小编在逛论坛的时候发现一个有关ecshop的BUG的帖子,现在发出来个大家分享下,如果朋友们遇到这个的问题可以作为参考修改. BUG描述如下: Ecshop没有点击邮件中的确认收货链接,但是进入个 ...

最新文章

  1. Eclipse 创建 Java 包
  2. 计算机科学与技术导论
  3. 002_centos7上安装mysql8
  4. 【机器学习】为什么在信用风险建模中首选树模型?
  5. 长连接和Keepalive
  6. jQuery序列化表单为JSON对象
  7. HTML+CSS+JS实现 ❤️3D万花筒图片相册展示特效❤️
  8. 如何用PS软件取得色块的颜色值?
  9. 二叉树前中后序遍历的口诀
  10. 2021年中国商业银行发展现状及龙头企业对比分析[图]
  11. 第六章:纯策略纳什均衡
  12. Android Studio:activity界面跳转时闪退或报错:xxx keeps stopping
  13. VS2010 调试警告 解决方法
  14. Zookeeper 客户端之 Curator
  15. html高德api,高德地图 Javascript API 入门(一)
  16. 王者怎么看微信以前玩过的服务器,王者荣耀如何查看微信帐号在那个区玩过
  17. AlphaFold2源码解析(10)--补充信息1(residue_constants)
  18. 三分钟了解http和https
  19. 利用Python 回归分析,四步预测广告收入 (附数据集与代码)
  20. Infortrend CS分布式NAS集群强项之---成本篇

热门文章

  1. rbd export V2
  2. 天空卫士与电子科技大学持续合作,助力数据安全人才培养
  3. 未受信任的企业级开发者_在 iOS 上安装自定企业级应用
  4. 音乐在计算机中的应用,计算机音乐技术在音乐教育中的应用
  5. 洛谷 1571 眼红的Medusa
  6. 开发者应知的 如何“推销自己”?
  7. 【微信小程序】上传字体文件自定义字体family
  8. Centos 7 虚拟机启动,Entering emergency mode问题解决
  9. Vue高频面试问题(含答案),面试官直呼好家伙~
  10. VS2017--无法添加引用--提示“未能完成操作。不支持此接口”