Springboot 整合 rocketmq及调度方案实现

最近新启动一个项目,用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

项目包结构

menu.saveimg.savepath20190403151126.jpg

实现详解

这里先讲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 deviceInfoList;

}
 
 
  • 消费者配置
    这里进行基础的配置,但并未启动监听,具体的监听交给具体的业务
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 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消费

  • 项目包结构


    menu.saveimg.savepath20190403180017.jpg

实现类详解

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 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);
                    }

你可能感兴趣的:(Springboot 整合 rocketmq及调度方案实现)