【CouponHub项目开发】使用RocketMQ5.x实现延时修改优惠券状态,并通过使用模板方法模式重构消息队列发送功能

在上个章节中我实现了创建优惠券模板的功能,但是,优惠券总会有过期时间,我们怎么去解决到期自动修改优惠券状态这样一个功能呢?我们可以使用RocketMQ5.x新出的任意定时发送消息功能来解决。

初始方案:

  • 首先在创建优惠券模板下面继续添加代码。首先先创建topic
  • 接着去定义消息体
java 复制代码
// 执行 RocketMQ5.x 消息队列发送&异常处理逻辑
    SendResult sendResult;
    try {
        sendResult = rocketMQTemplate.syncSendDeliverTimeMills(couponTemplateDelayCloseTopic, message, deliverTimeStamp);
        log.info("[生产者] 优惠券模板延时关闭 - 发送结果:{},消息ID:{},消息Keys:{}", sendResult.getSendStatus(), sendResult.getMsgId(), messageKeys);
    } catch (Exception ex) {
        log.error("[生产者] 优惠券模板延时关闭 - 消息发送失败,消息体:{}", couponTemplateDO.getId(), ex);
    }
  • 接着去调用相关方法去发送消息

这样一个延时发送的消息生产者就定义好了,接着我们去定义消费者。

  • 我们可以创建一个消费者类让他去实现RocketMQListener然后添加 @RocketMQMessageListener 注解,其中加上 Topic 和消费者组定义
  • 接着我们可以在onMessage方法内去定义我们接收到消息以后需要去做什么
  • 这里我们需要去修改数据库当中的优惠券的状态

这样就已经解决了定时修改优惠券模板状态这样的功能,但是这样直接写在代码当中不是太优雅,而且耦合度太高。我们可以通过去定义一个生产者的抽象类(模板),然后去通过定义具体的类来继承这些抽象类。然后在创建优惠券模板的方法中我们只需要去定义一个事件,然后调用该类的方法去发送消息即可。

java 复制代码
@RequiredArgsConstructor
@Slf4j(topic = "CommonSendProduceTemplate")
public abstract class AbstractCommonSendProduceTemplate<T> {

    private final RocketMQTemplate rocketMQTemplate;

    /**
     * 构建消息发送事件基础扩充属性实体
     *
     * @param messageSendEvent 消息发送事件
     * @return 扩充属性实体
     */
    protected abstract BaseSendExtendDTO buildBaseSendExtendParam(T messageSendEvent);

    /**
     * 构建消息基本参数,请求头、Keys...
     *
     * @param messageSendEvent 消息发送事件
     * @param requestParam     扩充属性实体
     * @return 消息基本参数
     */
    protected abstract Message<?> buildMessage(T messageSendEvent, BaseSendExtendDTO requestParam);

    /**
     * 消息事件通用发送
     *
     * @param messageSendEvent 消息发送事件
     * @return 消息发送返回结果
     */
    public SendResult sendMessage(T messageSendEvent) {
        BaseSendExtendDTO baseSendExtendDTO = buildBaseSendExtendParam(messageSendEvent);
        SendResult sendResult;
        try {
            // 构建 Topic 目标落点 formats: `topicName:tags`
            StringBuilder destinationBuilder = StrUtil.builder().append(baseSendExtendDTO.getTopic());
            if (StrUtil.isNotBlank(baseSendExtendDTO.getTag())) {
                destinationBuilder.append(":").append(baseSendExtendDTO.getTag());
            }

            // 延迟时间不为空,发送任意延迟消息,否则发送普通消息
            if (baseSendExtendDTO.getDelayTime() != null) {
                sendResult = rocketMQTemplate.syncSendDeliverTimeMills(
                        destinationBuilder.toString(),
                        buildMessage(messageSendEvent, baseSendExtendDTO),
                        baseSendExtendDTO.getDelayTime()
                );
            } else {
                sendResult = rocketMQTemplate.syncSend(
                        destinationBuilder.toString(),
                        buildMessage(messageSendEvent, baseSendExtendDTO),
                        baseSendExtendDTO.getSentTimeout()
                );
            }

            log.info("[生产者] {} - 发送结果:{},消息ID:{},消息Keys:{}", baseSendExtendDTO.getEventName(), sendResult.getSendStatus(), sendResult.getMsgId(), baseSendExtendDTO.getKeys());
        } catch (Throwable ex) {
            log.error("[生产者] {} - 消息发送失败,消息体:{}", baseSendExtendDTO.getEventName(), JSON.toJSONString(messageSendEvent), ex);
            throw ex;
        }

        return sendResult;
    }
}

在该抽象类中定义了两个抽象方法,

  • protected abstract BaseSendExtendDTO buildBaseSendExtendParam(T messageSendEvent);该方法用来补充事件的相关属性

  • protected abstract Message<?> buildMessage(T messageSendEvent, BaseSendExtendDTO requestParam);该方法是用来补充消息的属性

  • sendMessage方法中首先会通过buildBaseSendExtendParam方法把事件的属性进行补充,比如延时时间等。

  • 然后会获取这个时间是否存在延时时间这个属性,如果有则发送延时消息,如果没有,就发送普通消息。

这就是延时发送消息的生产者的一个实现类

这是消费者没有太大变化。

我们现在梳理一下它的执行流程

  • 创建完优惠券模板之后,我们根据优惠券的相关信息构建出一个发送事件templateDelayEvent
  • 然后通过自动注入的couponTemplateDelayExecuteStatusProducer延时发送消息的生产者,调用它的发送消息方法进行延时发送消息。
  • 这个生产者是去实现了生产者的一个抽象类,并实现了补充事件属性,以及构建消息体的抽象方法。
  • 然后消费者通过监听该消息来完成消费。
相关推荐
黄暄21 分钟前
微服务面试题(14题)
java·spring cloud·微服务·架构·java-rabbitmq·java-zookeeper
DKPT27 分钟前
如何设置JVM参数避开直接内存溢出的坑?
java·开发语言·jvm·笔记·学习
萤丰信息33 分钟前
智慧园区系统:开启园区管理与运营的新时代
java·大数据·人工智能·安全·智慧城市·智慧园区
一 乐34 分钟前
智慧党建|党务学习|基于SprinBoot+vue的智慧党建学习平台(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·学习
链上日记1 小时前
AIOT:用HealthFi重构全球健康金融体系的蓝海样本
人工智能·重构
不会编程的小寒1 小时前
C++ this指针、常函数、内联函数
java·开发语言
观望过往1 小时前
Spring Boot 集成 EMQ X 4.0 完整技术指南
java·spring boot·后端·emqx
ml魔力信息1 小时前
一枚指纹,开启工业IoT设备安全与权限分级实践
java·物联网·安全
会飞的小蛮猪2 小时前
SkyWalking运维之路(Java探针接入)
java·运维·经验分享·容器·skywalking
通域2 小时前
解决启动IDEA后CPU 及内存占用过高配置调整
java·ide·intellij-idea