最近新启动一个项目,用springboot开发,需要整合rocketmq,到网上收集了一下资料,大多都是一些简单的实现,类似于练习作业的那种。作为产品开发缺乏的东西太多。这里我给出完整的集成和消息调度方案,有不足之处欢迎留言指正。
配置
- 开发包引入,这里是基于gradle的配置,这里使用fastjson,方便对泛型的序列化和反序列化。这里mq的客户端版本需要和服务器端保持一致,否则可能造成每次应用重启都会重复消费之前的消息。
compile group: 'com.alibaba.rocketmq', name: 'rocketmq-client', version: '3.6.2.Final'
compile group:'com.alibaba',name:'fastjson',version:'1.2.8'
- 配置文件
rocketmq:
producer:
groupName: device_info_check
topic: device_info_check
namesrvAddr: 127.0.01:9876
sendMsgTimeout: 3000
retryTimesWhenSendFailed: 2
maxMessageSize: 4096
isOnOff: on
consumer:
groupName: device_info_check
topic: device_info_check
consumeMessageBatchMaxSize: 1
namesrvAddr: 127.0.0.1:9876
consumeThreadMax: 64
isOnOff: on
consumeThreadMin: 20
项目包结构
实现详解
这里先讲mq的集成,再讲消息发送的设计和消息消费的调度
- 生产者的配置
package com.jzl.tech.common.rocketMQ.producer;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
import com.jzl.tech.common.rocketMQ.constants.RocketMQErrorEnum;
import com.jzl.tech.common.rocketMQ.exception.RocketMQException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @ClassName MQProducerConfiguration
* @Description TODO
* @Author jzl
* @Date 2019/3/25 3:25 PM
* @Version 1.0
**/
@Configuration
public class MQProducerConfiguration {
public static final Logger LOGGER = LoggerFactory.getLogger(MQProducerConfiguration.class);
/**
* 发送同一类消息的设置为同一个group,保证唯一,默认不需要设置,rocketmq会使用ip@pid(pid代表jvm名字)作为唯一标示
*/
@Value("${rocketmq.producer.groupName}")
private String groupName;
@Value("${rocketmq.producer.namesrvAddr}")
private String namesrvAddr;
/**
* 消息最大大小,默认4M
*/
@Value("${rocketmq.producer.maxMessageSize}")
private Integer maxMessageSize ;
/**
* 消息发送超时时间,默认3秒
*/
@Value("${rocketmq.producer.sendMsgTimeout}")
private Integer sendMsgTimeout;
/**
* 消息发送失败重试次数,默认2次
*/
@Value("${rocketmq.producer.retryTimesWhenSendFailed}")
private Integer retryTimesWhenSendFailed;
@Bean
public DefaultMQProducer getRocketMQProducer() throws RocketMQException {
if(StringUtils.isEmpty(this.groupName)){
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"groupName is blank",false);
}
if (StringUtils.isEmpty(this.namesrvAddr)) {
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"nameServerAddr is blank",false);
}
DefaultMQProducer producer;
producer = new DefaultMQProducer(this.groupName);
producer.setNamesrvAddr(this.namesrvAddr);
producer.setCreateTopicKey("AUTO_CREATE_TOPIC_KEY");
//如果需要同一个jvm中不同的producer往不同的mq集群发送消息,需要设置不同的instanceName
//producer.setInstanceName(instanceName);
if(this.maxMessageSize!=null){
producer.setMaxMessageSize(this.maxMessageSize);
}
if(this.sendMsgTimeout!=null){
producer.setSendMsgTimeout(this.sendMsgTimeout);
}
//如果发送消息失败,设置重试次数,默认为2次
if(this.retryTimesWhenSendFailed!=null){
producer.setRetryTimesWhenSendFailed(this.retryTimesWhenSendFailed);
}
try {
producer.start();
LOGGER.info(String.format("producer is start ! groupName:[%s],namesrvAddr:[%s]"
, this.groupName, this.namesrvAddr));
} catch (MQClientException e) {
LOGGER.error(String.format("producer is error {}"
, e.getMessage(),e));
throw new RocketMQException(e);
}
return producer;
}
}
- 消息发送设计
消息发送接口
package com.jzl.tech.common.rocketMQ.producer;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessage;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessageBody;
public interface RocketMQMessageSender {
/***
* @description: 默认为异步发送
* @param [body] 消息体
* @return void
* @throws
* @date 2019/3/29
*/
void send(final T body);
/***
* @description: 消息是否同步发送
* @param [body, sync]
* @return void
* @throws
* @date 2019/3/29
*/
void send(final T body, final boolean sync);
/***
* @description: 直接转发消息
* @param [message]
* @return void
* @throws
* @date 2019/3/29
*/
void send(final RocketMQMessage message);
/***
* @description: 直接转发消息, 是否同步发送
* @param [message, sync]
* @return void
* @throws
* @date 2019/3/29
*/
void send(final RocketMQMessage message, final boolean sync);
}
消息发送实现类
package com.jzl.tech.common.rocketMQ.producer.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.common.message.Message;
import com.jzl.tech.common.rocketMQ.annotation.MessageType;
import com.jzl.tech.common.rocketMQ.constants.RocketMQErrorEnum;
import com.jzl.tech.common.rocketMQ.constants.RocketMqConst;
import com.jzl.tech.common.rocketMQ.exception.RocketMQException;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessage;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessageBody;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessageHead;
import com.jzl.tech.common.rocketMQ.producer.RocketMQMessageSender;
import com.jzl.tech.common.utils.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author jiazhenlong
* @title: RocketMQMessageSenderImpl
* @projectName Thor
* @description: mq消息发送
* @date 2019/3/29 13:23
*/
@Component
public class RocketMQMessageSenderImpl implements RocketMQMessageSender {
private static final Logger logger = LoggerFactory.getLogger(RocketMQMessageSenderImpl.class);
/**使用RocketMq的生产者*/
@Autowired
private DefaultMQProducer defaultMQProducer;
private ExecutorService executorService = Executors.newFixedThreadPool(10);
@Value("${rocketmq.producer.topic}")
private String deviceTopic;
private String redisTopic = "defaultTopic";
private Map topicMap = new HashMap();
@PostConstruct
private void init() {
topicMap.put(RocketMqConst.TYPE_REDIS, redisTopic);
topicMap.put(RocketMqConst.TYPE_DEVICE, deviceTopic);
}
@Override
public void send(T body) {
send(body, false);
}
@Override
public void send(T body, boolean sync) {
if (sync) {
syncSend(body);
} else {
executorService.execute(() -> {
syncSend(body);
});
}
}
private boolean syncSend(T body) {
// 获得请求消息封装类的注解
MessageType messageType = (MessageType) body.getClass().getAnnotation(MessageType.class);
// 检查注解是否存在
if (messageType == null) {
throw new RocketMQException(RocketMQErrorEnum.MESSAGE_BODY_NO_ANNOTATION,"msg type is null !!!",false);
}
// 构建消息
RocketMQMessage message = new RocketMQMessage(new RocketMQMessageHead(messageType.type(),
messageType.subType()), body);
// json 序列化时开启WriteClassName,反序列化时就可以直接把body里的泛型给反序列化回来
String msg = JSON.toJSONString(message, SerializerFeature.WriteClassName);
logger.info("rocketmq send:" + msg);
try {
SendResult result = defaultMQProducer.send(new Message(topicMap.get(messageType.type()),"DemoTag",msg.getBytes()));
logger.info(MessageFormat.format("发送响应:MsgId:{0}, 发送状态:{1}", result.getMsgId(), result.getSendStatus()));
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return false;
}
@Override
public void send(RocketMQMessage message) {
send(message, false);
}
@Override
public void send(RocketMQMessage message, boolean sync) {
if (sync) {
syncSend(message);
} else {
executorService.execute(() -> {
syncSend(message);
});
}
}
private void syncSend(RocketMQMessage message) {
try {
String json = JsonUtils.toString(message);
SendResult result = defaultMQProducer.send(
new Message(topicMap.get(message.getHead().getType()), json.getBytes()));
logger.info(MessageFormat.format("发送响应:MsgId:{0}, 发送状态:{1}", result.getMsgId(), result.getSendStatus()));
} catch (Exception e) {
logger.error("send mq message failed!", e);
}
}
}
- 消息报文设计
package com.jzl.tech.common.rocketMQ.message;
import lombok.Data;
import lombok.ToString;
/**
* @author jiazhenlong
* @title: RocketMQMessageHead
* @projectName Thor
* @description: 消息头
* @date 2019/3/28 17:03
*/
@ToString
@Data
public class RocketMQMessageHead {
/**
* 消息类型
*/
private int type;
/**
* 子类型
*/
private String subType;
/**
* 发送消息的时间戳
*/
private long timestamp;
public RocketMQMessageHead() {
timestamp = System.currentTimeMillis();
}
public RocketMQMessageHead(int type, String subType) {
this.type = type;
this.subType = subType;
this.timestamp = System.currentTimeMillis();
}
}
消息体基类
package com.jzl.tech.common.rocketMQ.message;
/**
* @author jiazhenlong
* @title: RocketMQMessageBody
* @projectName Thor
* @description: RocketMQ的消息体,继承这个类,这个基类没什么用,主要作用就是限制RocketMQ消息发送的类型,不能发送任意Object
* @date 2019/3/28 16:52
*/
public class RocketMQMessageBody {
}
消息
package com.jzl.tech.common.rocketMQ.message;
import lombok.Data;
import lombok.ToString;
/**
* @author jiazhenlong
* @title: RocketMQMessage
* @projectName Thor
* @description: RocketMQ消息
* @date 2019/3/28 16:56
*/
@ToString
@Data
public class RocketMQMessage {
private RocketMQMessageHead head;
private T body;
public RocketMQMessage(RocketMQMessageHead head, T body) {
this.head = head;
this.body = body;
}
}
具体业务对应的消息体
package com.jzl.tech.common.rocketMQ.message.body;
import com.jzl.tech.common.rocketMQ.annotation.MessageType;
import com.jzl.tech.common.rocketMQ.constants.RocketMqConst;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessageBody;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.List;
/**
* @author jiazhenlong
* @title: DeviceInfoCheckReq
* @projectName Thor
* @description: 设备信息检查mq对象
* @date 2019/3/29 10:49
*/
@EqualsAndHashCode(callSuper = true)
@ToString
@Data
@MessageType(type = RocketMqConst.TYPE_DEVICE, subType = RocketMqConst.DEVICE_INFO_CHECK)
public class DeviceInfoCheckReq extends RocketMQMessageBody {
/**
* 命令
*/
private String commandStr;
/**
* 功能
*/
private List
- 消费者配置
这里进行基础的配置,但并未启动监听,具体的监听交给具体的业务
package com.jzl.tech.common.rocketMQ.consumer;
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.common.consumer.ConsumeFromWhere;
import com.jzl.tech.common.rocketMQ.constants.RocketMQErrorEnum;
import com.jzl.tech.common.rocketMQ.exception.RocketMQException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
/**
* @ClassName MQConsumerConfiguration
* @Description TODO
* @Author gw
* @Date 2019/3/25 3:34 PM
* @Version 1.0
**/
@Configuration
public class MQConsumerConfiguration {
public static final Logger logger = LoggerFactory.getLogger(MQConsumerConfiguration.class);
@Value("${rocketmq.consumer.namesrvAddr}")
private String namesrvAddr;
@Value("${rocketmq.consumer.groupName}")
private String groupName;
@Value("${rocketmq.consumer.consumeThreadMin}")
private int consumeThreadMin;
@Value("${rocketmq.consumer.consumeThreadMax}")
private int consumeThreadMax;
@Value("${rocketmq.consumer.topic}")
private String topics;
@Value("${rocketmq.consumer.consumeMessageBatchMaxSize}")
private int consumeMessageBatchMaxSize;
@Bean
public DefaultMQPushConsumer getRocketMQConsumer() throws RocketMQException{
if (StringUtils.isEmpty(groupName)){
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"groupName is null !!!",false);
}
if (StringUtils.isEmpty(namesrvAddr)){
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"namesrvAddr is null !!!",false);
}
if(StringUtils.isEmpty(topics)){
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"topics is null !!!",false);
}
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(groupName);
consumer.setNamesrvAddr(namesrvAddr);
consumer.setConsumeThreadMin(consumeThreadMin);
consumer.setConsumeThreadMax(consumeThreadMax);
/**
* 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费
* 如果非第一次启动,那么按照上次消费的位置继续消费
*/
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
/**
* 设置消费模型,集群还是广播,默认为集群
*/
//consumer.setMessageModel(MessageModel.CLUSTERING);
/**
* 设置一次消费消息的条数,默认为1条
*/
consumer.setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize);
try {
/**
* 设置该消费者订阅的主题和tag,如果是订阅该主题下的所有tag,
* 则tag使用*;如果需要指定订阅该主题下的某些tag,则使用||分割,例如tag1||tag2||tag3
*/
/*String[] topicTagsArr = topics.split(";");
for (String topicTags : topicTagsArr) {
String[] topicTag = topicTags.split("~");
consumer.subscribe(topicTag[0],topicTag[1]);
}*/
consumer.subscribe(topics, "*");
// consumer.start();
//logger.info("consumer is start !!! groupName:{},topics:{},namesrvAddr:{}",groupName,topics,namesrvAddr);
} catch (Exception e) {
// logger.error("consumer is start !!! groupName:{},topics:{},namesrvAddr:{}",groupName,topics,namesrvAddr,e);
throw new RocketMQException(e);
}
return consumer;
}
}
监听类
package com.jzl.tech.common.rocketMQ.consumer;
import com.alibaba.fastjson.JSON;
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.common.message.MessageExt;
import com.jzl.tech.common.rocketMQ.handler.RocketMQMessageHandler;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessage;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessageBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.text.MessageFormat;
import java.util.List;
/**
* @ClassName MQConsumeMsgListenerProcessor
* @Description 消息监听
* @Author gw
* @Date 2019/3/25 3:36 PM
* @Version 1.0
**/
public class MQConsumeMsgListenerProcessor {
private static final Logger logger = LoggerFactory.getLogger(MQConsumeMsgListenerProcessor.class);
/**
* 消息有效期,暂定为1小时
*/
private static final long VALID_INTERVAL = 1000 * 60 * 60;
/**
* 消息处理接口
*/
private RocketMQMessageHandler rocketMQMessageHandler;
/**
* 消费者
*/
private DefaultMQPushConsumer consumer;
/**
* mq topic
*/
private String topic;
public MQConsumeMsgListenerProcessor(RocketMQMessageHandler rocketMQMessageHandler,
DefaultMQPushConsumer consumer,
String topic) throws MQClientException {
this.consumer = consumer;
this.rocketMQMessageHandler = rocketMQMessageHandler;
this.consumer.subscribe(topic,"*");
}
/***
* @description:
* @param
* @return void
* @throws
* @date 2019/4/1
*/
public void recevieConcurently() {
try {
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) {
if(CollectionUtils.isEmpty(msgs)){
logger.info("接收到的消息为空,不做任何处理");
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
MessageExt messageExt = msgs.get(0);
String msg = new String(messageExt.getBody());
logger.info("接收到的消息是:" + msg);
int reconsumeTimes = messageExt.getReconsumeTimes();
if(reconsumeTimes == 3){
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
RocketMQMessage extends RocketMQMessageBody> rocketMQMessage = JSON.parseObject(messageExt.getBody(), RocketMQMessage.class);
if (System.currentTimeMillis()
- rocketMQMessage.getHead().getTimestamp() > VALID_INTERVAL) {
// 如果消息是有效期之前发送的,不做任何处理
logger.info("rocketMQ message expired:message=" + rocketMQMessage.toString());
} else {
rocketMQMessageHandler.handle(rocketMQMessage);
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
this.consumer.start();
} catch (Exception e) {
logger.info(MessageFormat.format("mq消息接收失败, exception={0}", e.getMessage()) , e);
}
}
}
应用接入mq消费
-
项目包结构
实现类详解
mq消息接收启动类
package com.jzl.tech.rocketmq.comsumer;
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.jzl.tech.common.rocketMQ.consumer.MQConsumeMsgListenerProcessor;
import com.jzl.tech.common.rocketMQ.handler.RocketMQMessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author jiazhenlong
* @title: RocketMQMessageReceiver
* @projectName Thor
* @description: mq消息接收类定义
* @date 2019/4/2 10:18
*/
@Component
public class RocketMQMessageReceiver {
@Autowired
private DefaultMQPushConsumer defaultMQPushConsumer;
@Autowired
private RocketMQMessageHandler rocketMQMessageHandler;
@Value("${rocketmq.producer.topic}")
private String deviceTopic;
@PostConstruct
private void init() throws MQClientException {
new MQConsumeMsgListenerProcessor(rocketMQMessageHandler, defaultMQPushConsumer, deviceTopic).recevieConcurently();
}
}
消息分发
package com.jzl.tech.rocketmq.handler;
import com.jzl.tech.common.rocketMQ.handler.RocketMQMessageHandler;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessage;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessageBody;
import com.jzl.tech.rocketmq.devicecheck.DeviceInfoCheckHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author jiazhenlong
* @title: DeviceRocketMQMessageHandler
* @projectName Thor
* @description: 消息处理
* @date 2019/4/2 10:32
*/
@Component
public class DeviceRocketMQMessageHandler implements RocketMQMessageHandler {
private static final Logger logger = LoggerFactory.getLogger(DeviceRocketMQMessageHandler.class);
@Autowired
private Map deviceInfoCheckHandlerMap;
@Override
public void handle(RocketMQMessage rocketMQMessage) {
deviceInfoCheckHandlerMap.get(rocketMQMessage.getHead().getSubType()).handle(rocketMQMessage.getBody());
}
}
具体业务处理类
package com.jzl.tech.rocketmq.devicecheck;
import com.jzl.tech.common.rocketMQ.message.RocketMQMessageBody;
/**
* @author jiazhenlong
* @title: DeviceInfoCheckHandler
* @projectName Thor
* @description: 设备监控接口
* @date 2019/4/2 13:40
*/
public interface DeviceInfoCheckHandler {
/***
* @description: 处理mq消息
* @param [messageBody]
* @return void
* @throws
* @date 2019/4/2
*/
public void handle(T messageBody);
}
package com.jzl.tech.rocketmq.devicecheck.impl;
import com.jzl.tech.common.rocketMQ.message.body.DeviceInfoCheckReq;
import com.jzl.tech.rocketmq.devicecheck.DeviceInfoCheckHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @author jiazhenlong
* @title: DeviceInfoCheckHandlerImpl
* @projectName Thor
* @description: 处理设备监控
* @date 2019/4/2 13:40
*/
@Component
public class DeviceInfoCheckHandlerImpl implements DeviceInfoCheckHandler {
private static final Logger log = LoggerFactory.getLogger(DeviceInfoCheckHandlerImpl.class);
@Override
public void handle(DeviceInfoCheckReq messageBody) {
//处理业务
log.info(messageBody.toString());
}
}
注解
package com.jzl.tech.common.rocketMQ.annotation;
import java.lang.annotation.*;
/**
* @author jiazhenlong
* @title: MessageType
* @projectName Thor
* @description: 处理消息类型注解类 在需要处理的消息类的类上声明该注解,指明类型和子类型即,在handle方法中写消息处理逻辑即可
* @date 2019/3/29 10:49
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MessageType {
/**
* 类型
*
* @return
*/
int type();
/**
* 子类型,该字段为具体业务实现类的名称
*
* @return
*/
String subType();
}
消息类型定义
package com.jzl.tech.common.rocketMQ.constants;
/**
* @author jiazhenlong
* @title: RocketMqConst
* @projectName Thor
* @description: 消息类型常量
* @date 2019/3/29 11:09
*/
public class RocketMqConst {
/**
* 刷新redis缓存
*/
public static final int TYPE_REDIS = 1;
/**
* 设备
*/
public static final int TYPE_DEVICE = 2;
/**
* 设备信息检查,这里默认为实现类的名称
*/
public static final String DEVICE_INFO_CHECK = "deviceInfoCheckHandlerImpl";
}
当然消费者端也可以用topic+tag的方式去调用业务实现类,这里给个简单的例子。
RocketMQMessage extends RocketMQMessageBody> rocketMQMessage = JSON.parseObject(messageExt.getBody(), RocketMQMessage.class);
if (System.currentTimeMillis()
- rocketMQMessage.getHead().getTimestamp() > VALID_INTERVAL) {
// 如果消息是有效期之前发送的,不做任何处理
logger.info("rocketMQ message expired:message=" + rocketMQMessage.toString());
} else {
rocketMQMessage.setHead().setSubType(topic + tag);
rocketMQMessageHandler.handle(rocketMQMessage);
}