需求分析:

javashop电商系统中,各种促销活动都有开始时间和结束时间,想要让一个活动在预定的时间开始或结束,使用定时任务轮询,存在耗性能并且不能在准确的时间点开始或结束的缺点,为了可以在指定的时间执行,要求使用延时任务

思路:

延时任务:指定某日期执行某自定义任务

思路为采用Rabbitmq中的死信转移队列的技术点实现。

第一步向一个队列(具有xxxx属性)发送消息,这个队列的消息可以指定失效时间

当失效发生时rabbbitmq会将此消息转移到另外的一个普通对列中,此时立刻被消费了,以此实现任务的延迟执行。

AMQP 延时任务核心类图

TimeTrigger 触发器接口,对外提供定义延迟任务的接口,调用者直接面向此接口。

目前只实现了基于RabbitMq的实现,如果有其他延时任务实现(如基于redis),面向此接口开发即可,定义新增、编辑、删除任务操作。

RabbitmqTimeTrigger

基于rabbitmq延时任务实现

TimeTriggerConfig,rabbitmq配置

TimeTriggerMsg,rabbitmq延时任务消息

执行器类图

TimeTriggerConsumer 延时任务消费者,负责延时任务的调用

TimeTriggerExecuter 延时任务执行器接口,自定义延时任务需要实现此接口

PintuanTimeTriggerExecuter 以拼团业务为例,延时任务执行的实现。

新增任务时序图

步骤说明:

1、新增延时任务,指定延时任务所需的参数(执行器beanName,执行器参数,执行日期,执行任务标识KEY)

2、rabbitmq发送消息,将执行器以及参数封装

3、写入redis,标识任务需要执行

4、mq监听 指定时间任务

5、消费者获取redis的任务标识

7、进行标识判断,如果判断无效,则不执行任务,return

8、如果任务标识有效,则通过springbean容器获取执行器,执行execute方法

编辑任务流程图

步骤说明:

1、编辑延时任务,指定延时任务所需的参数(执行器,执行器参数,执行日期,执行任务标识KEY)

2、删除redis中的任务标识,代表任务取消

3、rabbitmq发送消息,将执行器以及参数封装

4、写入redis,标识任务需要执行

5、mq监听 指定时间任务

7、消费者获取redis的任务标识

8、进行标识判断,如果判断无效,则不执行任务,return

9、如果任务标识有效,则通过springbean容器获取执行器,执行execute方法

删除任务流程图

步骤说明:

1、删除延时任务,参数(执行任务标识KEY)

2、删除redis中的任务标识,代表任务取消

源码

TimeTriggerConsumer 延时任务消费者,负责延时任务的调用

package com.enation.app.javashop.framework.trigger.rabbitmq;import com.enation.app.javashop.framework.cache.Cache;import com.enation.app.javashop.framework.trigger.Interface.TimeTrigger;import com.enation.app.javashop.framework.trigger.rabbitmq.model.TimeTriggerMsg;import com.enation.app.javashop.framework.trigger.util.RabbitmqTriggerUtil;import com.enation.app.javashop.framework.util.DateUtil;import com.enation.app.javashop.framework.util.StringUtil;import com.enation.app.javashop.framework.logs.Logger;import com.enation.app.javashop.framework.logs.LoggerFactory;import org.springframework.amqp.rabbit.core.RabbitTemplate;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;/** * 延时任务生产 rabbitmq实现 * @Description: 原理:利用amqp的死信队列的超时属性,将超时的任务转到普通队列交给消费者执行。 * 添加任务,将任务执行标识、beanid、执行时间,hash值存入redis,标识任务需要执行 * 添加删除,删除redis中的任务标识,消费者执行时获取不到 redis中的标识,则不会执行延时任务 * 

*/@Componentpublic class RabbitmqTimeTrigger implements TimeTrigger { /** * 引入rabbit的操作模板 */ @Autowired private RabbitTemplate rabbitTemplate; @Autowired private Cache cache; private final Logger logger = LoggerFactory.getLogger(getClass()); /** * 添加延时任务 * * @param executerName 执行器 * @param param 执行参数 * @param triggerTime 执行时间 * @param uniqueKey 如果是一个 需要有 修改/取消 延时任务功能的延时任务,
* 请填写此参数,作为后续删除,修改做为唯一凭证
* 建议参数为:PINTUAZN_{ACTIVITY_ID} 例如 pintuan_123
* 业务内全局唯一 */ @Override public void add(String executerName, Object param, Long triggerTime, String uniqueKey) { if (StringUtil.isEmpty(uniqueKey)) { uniqueKey = StringUtil.getRandStr(10); } //标识任务需要执行 cache.put(RabbitmqTriggerUtil.generate(executerName, triggerTime, uniqueKey), 1); TimeTriggerMsg timeTriggerMsg = new TimeTriggerMsg(executerName, param, triggerTime, uniqueKey); logger.debug("定时执行在【" + DateUtil.toString(triggerTime, "yyyy-MM-dd HH:mm:ss") + "】,消费【" + param.toString() + "】"); rabbitTemplate.convertAndSend(TimeTriggerConfig.DELAYED_EXCHANGE_XDELAY, TimeTriggerConfig.DELAY_ROUTING_KEY_XDELAY, timeTriggerMsg, message -> { Long current = DateUtil.getDateline(); //如果执行的延时任务应该是在现在日期之前执行的,那么补救一下,要求系统一秒钟后执行 if (triggerTime < current) { message.getMessageProperties().setDelay(1000); } else { Long time = (triggerTime - current) * 1000 + 5000 ; message.getMessageProperties().setHeader("x-delay", time); } logger.debug("还有【" + message.getMessageProperties().getExpiration() + "】执行任务"); return message; }); } /** * 修改延时任务 * * @param executerName 执行器 * @param param 执行参数 * @param triggerTime 执行时间 * @param uniqueKey 添加任务时的唯一凭证 */ @Override public void edit(String executerName, Object param, Long oldTriggerTime, Long triggerTime, String uniqueKey) { //标识任务放弃 cache.remove(RabbitmqTriggerUtil.generate(executerName, oldTriggerTime, uniqueKey)); //重新添加任务 this.add(executerName, param, triggerTime, uniqueKey); } /** * 删除延时任务 * * @param executerName 执行器 * @param triggerTime 执行时间 * @param uniqueKey 添加任务时的唯一凭证 */ @Override public void delete(String executerName, Long triggerTime, String uniqueKey) { cache.remove(RabbitmqTriggerUtil.generate(executerName, triggerTime, uniqueKey)); }}

TimeTriggerExecuter 延时任务执行器接口,自定义延时任务需要实现此接口

package com.enation.app.javashop.framework.trigger.Interface;/** * 延时任务执行器接口 * */public interface TimeTriggerExecuter {    /**     * 执行任务     * @param object 任务参数     */    void execute(Object object);}

PintuanTimeTriggerExecuter 以拼团业务为例,延时任务执行的实现。

package com.enation.app.javashop.consumer.shop.trigger;import com.enation.app.javashop.core.base.message.PintuanChangeMsg;import com.enation.app.javashop.core.base.rabbitmq.TimeExecute;import com.enation.app.javashop.core.promotion.pintuan.model.Pintuan;import com.enation.app.javashop.core.promotion.pintuan.model.PintuanOptionEnum;import com.enation.app.javashop.core.promotion.pintuan.service.PintuanManager;import com.enation.app.javashop.core.promotion.tool.model.enums.PromotionStatusEnum;import com.enation.app.javashop.framework.trigger.Interface.TimeTrigger;import com.enation.app.javashop.framework.trigger.Interface.TimeTriggerExecuter;import com.enation.app.javashop.framework.logs.Logger;import com.enation.app.javashop.framework.logs.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;/** * 拼团定时开启关闭活动 延时任务执行器 * * @author Chopper * @version v1.0 * @since v7.0 * 2019-02-13 下午5:34 */@Component("pintuanTimeTriggerExecute")public class PintuanTimeTriggerExecuter implements TimeTriggerExecuter {    @Autowired    private TimeTrigger timeTrigger;    @Autowired    private PintuanManager pintuanManager;    private final Logger logger = LoggerFactory.getLogger(getClass());    /**     * 执行任务     *     * @param object 任务参数     */    @Override    public void execute(Object object) {        PintuanChangeMsg pintuanChangeMsg = (PintuanChangeMsg) object;        //如果是要开启活动        if (pintuanChangeMsg.getOptionType() == 1) {            Pintuan pintuan = pintuanManager.getModel(pintuanChangeMsg.getPintuanId());            if (PromotionStatusEnum.WAIT.name().equals(pintuan.getStatus()) ||                    (PromotionStatusEnum.END.name().equals(pintuan.getStatus()) && PintuanOptionEnum.CAN_OPEN.name().equals(pintuan.getOptionStatus()))) {                pintuanManager.openPromotion(pintuanChangeMsg.getPintuanId());                //开启活动后,立马设置一个关闭的流程                pintuanChangeMsg.setOptionType(0);                timeTrigger.add(TimeExecute.PINTUAN_EXECUTER, pintuanChangeMsg, pintuan.getEndTime(), "{TIME_TRIGGER}_" + pintuan.getPromotionId());                this.logger.debug("活动[" + pintuan.getPromotionName() + "]开始,id=[" + pintuan.getPromotionId() + "]");            }        } else {            //拼团活动结束            Pintuan pintuan = pintuanManager.getModel(pintuanChangeMsg.getPintuanId());            if (pintuan.getStatus().equals(PromotionStatusEnum.UNDERWAY.name())) {                pintuanManager.closePromotion(pintuanChangeMsg.getPintuanId());            }            this.logger.debug("活动[" + pintuan.getPromotionName() + "]结束,id=[" + pintuan.getPromotionId() + "]");        }    }}

机票预定系统类图_电商系统延时任务机制源码分享相关推荐

  1. 电商系统延时任务机制源码分享

    需求分析: 在javashop电商系统中,各种促销活动都有开始时间和结束时间,想要让一个活动在预定的时间开始或结束,使用定时任务轮询,存在耗性能并且不能在准确的时间点开始或结束的缺点,为了可以在指定的 ...

  2. java超市购物系统类图_毕业设计超市系统(一)UML 建模

    学校的毕业设计要求是很严格的,导师也不管你做的程序怎么样就是严格要求文档.文档一共改了五次,我用面向对象的方法来构造整个系统,还好老师没有提出什么雷人的说法(一个同学也用这种方法做,被导师骂了一通.说 ...

  3. 开源商城系统iWebShop、社交电商系统iWebSNS官方团队启用“数开”双拼域名

    聚易技术,jooyea tech,知名开源商城系统iWebShop.社交电商系统iWebSNS的官方团队启用"数开"双拼域名. http://www.shukai.com.价格不菲 ...

  4. JAVA毕业设计O2O生鲜果蔬电商设计与实现计算机源码+lw文档+系统+调试部署+数据库

    JAVA毕业设计O2O生鲜果蔬电商设计与实现计算机源码+lw文档+系统+调试部署+数据库 JAVA毕业设计O2O生鲜果蔬电商设计与实现计算机源码+lw文档+系统+调试部署+数据库 本源码技术栈: 项目 ...

  5. java计算机毕业设计ssm木棉堂水果电商平台1r83i(附源码、数据库)

    java计算机毕业设计ssm木棉堂水果电商平台1r83i(附源码.数据库) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ ...

  6. 商城项目01 _电商系统基本模式、分布式基础概念、微服务架构图、微服务划分图

    文章目录 ①. 电商系统基本模式 ②. 分布式基础概念 ③. 微服务架构图详解 ④. 微服务划分图 ①. 电商系统基本模式 ①. B2C模式 就是我们经常看到的供应商直接把商品卖给用户,即" ...

  7. 一个页面区分管理者和普通用户如何设计_电商系统:优惠券原型设计说明(二)...

    编辑导读:在整个产品发展的整个周期中,运营活动必不可少,而发放优惠券已成为运营活动的一种基本形式,而关于优惠券设计就尤为重要.本文作者分享了优惠券后台页面的相关设计步骤,推荐给对优惠券感兴趣的童鞋阅读 ...

  8. 计算机毕业设计SSM电商后台管理系统【附源码数据库】

    项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclis ...

  9. APICloud AVM多端开发 |《生鲜电商app开发》项目源码深度解析

    此项目为生鲜电商app开发类应用,主要功能包括商品列表.商品详情展示.购物车.登录注册.个人中心等. 项目源码在 https://github.com/apicloudcom/avm-simple 仓 ...

最新文章

  1. 图灵5周年系列活动之科普大爆炸(免费!)
  2. linux进程管理笔记
  3. JMX和Spring –第1部分
  4. spring data jpa 的 in 查询 Specification 实现
  5. Qt文档阅读笔记-Rotations Example相关
  6. 如何打造标准化的数据治理评估体系?
  7. JDK8相对于JDK7的一些新特性
  8. redisTemplate.keys异常
  9. A.I. Wiki 人工智能
  10. 2021年危险化学品生产单位安全生产管理人员新版试题及危险化学品生产单位安全生产管理人员找解析
  11. java游戏后端日志【6】 -- 初生牛犊不怕虎?
  12. 程序员如何做SOHO一族接私单做呢?
  13. RPLIDAR思岚雷达学习记录--6--matlab处理雷达数据
  14. [WebView] - WebView leaked
  15. PS制作压印效果的logo等
  16. #loj3059 HNOI2019 序列
  17. 熊掌号PHP,百度熊掌号广受站长关注,phpcm网站程序的熊掌号页面改造插件也火了!...
  18. 如何实现SQL中加减乘除等四则运算
  19. Java(老白再次入门) - 语言概述
  20. 传奇服务器文件,【教程】传奇服务端(版本)的结构以及重要文件功能的概述-A02...

热门文章

  1. UFLDL 教程学习笔记(一)
  2. Hello Cnblog!
  3. Eliminate Witches!【2011年北京赛区正赛赛题-2】
  4. 清除重复记录只保留一条
  5. 读书笔记 -《深入理解计算机系统》2.1
  6. java扫描包内所有类_第20天|Java入门有野,修饰符
  7. z最大子数组c语言,关于最大子数组问题
  8. SpringMVC_1.认识MVC
  9. android tcp tcp阻塞 线程不运行,Android tcp优化
  10. php对象里面存对象,PHP:在$ _SESSION中存储'对象'