RockietMQ实战(自己封装一下)

spring管理配置实体类



​
    
    
​
    
        
        
        
        
        
        
        
            
        
    

发送RocketMQ消息 SendMsgMQService.java

import com.alibaba.fastjson.JSON;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.tf56.hermesContract.model.HermesContract;
import com.tf56.hermesContractApi.DTO.EContractSendMqDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import tf56.shared.rocketmq.TfmqClient;
​
import javax.annotation.Resource;
​
@Service
@Slf4j
public class SendMsgMQService {
​
    @Resource
    private TfmqClient tfmqClient;
    @Value("${rocketmq.producer.topic}")
    private String eContractTopic;
    @Value("${rocketmq.producer.topic}")
    private String tag;
​
    public void sendContractMQ(HermesContract hc){
        EContractSendMqDTO dto = new EContractSendMqDTO();// 消息体对象
        // 业务处理
        
        SendResult sr = tfmqClient.sendUTF(eContractTopic, tag, hc.getContractNum(), JSON.toJSONString(dto));
        log.info("状态变更MQ消息:合同编号[{}],状态[{}],send[{}]",hc.getContractNum(),hc.getContractStatus(),JSON.toJSONString(sr));
    }
​
}
​

监听RocketMQ消息 RocketMqMessageConsumer.java

import com.alibaba.fastjson.JSON;
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.common.message.MessageExt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
​
import java.nio.charset.StandardCharsets;
import java.util.List;
​
/**
 * mq消息监听
 */
@SuppressWarnings("Duplicates")
@Slf4j
@Service
public class RocketMqMessageConsumer implements MessageListenerConcurrently {
​
    /**
     * 此topic、tag与applicationContext-mqClient.xml中consumerTopicTags配置相对应
     */
    @Value("${rocketmq.consumer.topic}")
    private String topic;
    @Value("${rocketmq.consumer.tag}")
    private String tag;
​
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List msgs, ConsumeConcurrentlyContext context) {
        for (MessageExt msg : msgs) {
            String msgBody = new String(msg.getBody(), StandardCharsets.UTF_8);
            log.info("MQ消息体:{}", msgBody);
            if(topic.equals(msg.getTopic()) && tag.equals(msg.getTags())){
                ContractSendSignFileMqDTO mqDTO = JSON.parseObject(msgBody, ContractSendSignFileMqDTO.class);
                // 处理业务代码
                // TODO
                return ConsumeConcurrentlyStatus.RECONSUME_LATER;// 处理失败
            }
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
}
​

 

TfmqClient.java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.common.message.Message;
​
/**
 * RocketMqClient封装类,包含DefaultMQPushConsumer,DefaultMQProducer。
 * 
 * 设计说明:
 * 1.1.1, 支持同时连接多个集群(多套namesrv)
 * 
 * 1.2.1, 简化API,支持扩展,更好支持消息跟踪。v1.0.0重载了太多方法,选择困难。
 * 1.2.2, 全部废弃v1.0.0的API,为了避免,升级版本忘记切换方法。
 * 
 * 使用说明:
 * 1.1,DefaultMQPushConsumer自动启动充要条件:consumerNamesrvAddr,consumerGroupName,consumerTopicTags, messageListener 配置正确齐全
 * 1.2,consumerTopicTags:格式形如:topic1,tag1;topic2,tag2 或 topic1;topic2 或 topic1。详情{TfmqFactory.java}
 * 
 * 2.1,DefaultMQProducer自动启动充要条件:producerNamesrvAddr,producerGroupName 配置正确齐全
 * 
 * 3.1,目前仅支持log4j日志,其他日志如logback请自行检查
 * 
* * @version 1.1.0 * @author naijiang.wang * @date 2016年10月17日 下午7:56:17 */ public class TfmqClient { private static final Logger logger = LoggerFactory.getLogger(TfmqClient.class); private DefaultMQPushConsumer consumer; private DefaultMQProducer producer; private MessageListenerConcurrently messageListener; private String producerNamesrvAddr; private String producerGroupName; private String consumerNamesrvAddr; private String consumerGroupName; private String consumerTopicTags; private boolean started = false; ​ public synchronized void init() throws MQClientException { if (!started) { startProducer(); startConsumer(); registerHook(); started = true; } } ​ private void startProducer() throws MQClientException { producer = TfmqFactory.newDefaultMQProducer(producerGroupName, producerNamesrvAddr); if (producer != null) { logger.info("producer starting..."); producer.start(); logger.info("producer started OK..."); } } ​ private void startConsumer() throws MQClientException { consumer = TfmqFactory.newDefaultMQPushConsumer(consumerGroupName, consumerNamesrvAddr, messageListener, consumerTopicTags); if (consumer != null) { logger.info("consumer starting..."); consumer.start(); logger.info("consumer started OK..."); } } /** * 释放资源,关闭客户端, tomcat环境下使用 */ public synchronized void destroy(){ logger.info("开始调用destroy()方法,started="+started); if(started){ logger.info("开始执行destroy()方法,started="+started); destroyProducer(); destroyConsumer(); started = false; } } ​ /** * 非tomcat应用的关闭钩子 *
     * Runtime.getRuntime().addShutdownHook注释:
     * it will start all registered shutdown hooks in some unspecified order and let them run concurrently.
     * tomcat自身也有CatalinaShutdownHook。使用tomcat的shutdown.sh会报以下错误:
     * 16:31:56.627 [Thread-6] INFO  TfmqClient - producer shutdowning...1f190f5193fd6afb220cd10d2b136bbd
Exception in thread "Thread-6" java.lang.IllegalStateException: Can't overwrite cause with java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [ch.qos.logback.classic.spi.ThrowableProxy]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
        at java.lang.Throwable.initCause(Throwable.java:456)
        at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1324)
        at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1203)
        at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1164)
        at ch.qos.logback.classic.spi.LoggingEvent.(LoggingEvent.java:125)
        at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:468)
        at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:424)
        at ch.qos.logback.classic.Logger.error(Logger.java:587)
        at java.lang.Thread.run(Thread.java:744)
     * 
*/ private void registerHook() { Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { logger.info("ShutdownHook开始调用destroy()方法,started="+started); destroy(); } })); } /** * 发送mq消息, msg使用utf-8编码。 *
     * 消息跟踪有两种方式:
     * 1, SendResult中的msgId
     * 2, topic + keys 组合方式
     * 
* @param topic * @param tags 不需要时传 null 或者 空串 "" * @param keys 用于消息跟踪。最好使用不会重复的值,比如交易Num之类的。 * @param msg 消息体字符串,使用utf-8编码 * @throws TfmqException */ public SendResult sendUTF(String topic, String tags, String keys, String msg) throws TfmqException{ SendResult sendResult; if(tags == null){ tags = ""; } if(keys == null){ keys = ""; } try { Message message = new Message(topic, tags, keys, msg.getBytes("utf-8")); sendResult = producer.send(message); } catch (Exception e) { throw new TfmqException("tfmq发送消息失败", e); } return sendResult; } /** * 发送mq消息,可自定义message属性 *
     * //设置延迟等级,默认不设置,没有延迟 。从1开始。对应的值:"1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"
     * 1, message.setDelayTimeLevel(delayTimeLevel); 
     * 2, 其他详见com.alibaba.rocketmq.common.message.Message构造方法
     * 
*/ public SendResult send(Message message)throws TfmqException { SendResult sendResult; try { sendResult = producer.send(message); } catch (Exception e) { throw new TfmqException("tfmq发送消息失败", e); } return sendResult; } ​ private void destroyProducer(){ // RocketMq服务器上注销自己 try { if (null != producer) { String instanceName = producer.getInstanceName(); logger.info("producer shutdowning..."+instanceName); producer.shutdown(); producer = null; logger.info("producer shutdown OK.."+instanceName); } } catch (Exception e) { logger.error("destroyProducer发生异常", e); } } private void destroyConsumer(){ // RocketMq服务器上注销自己 try { if (null != consumer) { String instanceName = consumer.getInstanceName(); logger.info("consumer shutdowning..."+instanceName); consumer.shutdown(); consumer = null; logger.info("consumer shutdown OK.."+instanceName); } } catch (Exception e) { logger.error("destroyConsumer发生异常", e); } } public MessageListenerConcurrently getMessageListener() { return messageListener; } ​ public void setMessageListener(MessageListenerConcurrently messageListener) { this.messageListener = messageListener; } ​ public String getProducerNamesrvAddr() { return producerNamesrvAddr; } ​ public void setProducerNamesrvAddr(String producerNamesrvAddr) { this.producerNamesrvAddr = producerNamesrvAddr; } ​ public String getProducerGroupName() { return producerGroupName; } ​ public void setProducerGroupName(String producerGroupName) { this.producerGroupName = producerGroupName; } ​ public String getConsumerNamesrvAddr() { return consumerNamesrvAddr; } ​ public void setConsumerNamesrvAddr(String consumerNamesrvAddr) { this.consumerNamesrvAddr = consumerNamesrvAddr; } ​ public String getConsumerGroupName() { return consumerGroupName; } ​ public void setConsumerGroupName(String consumerGroupName) { this.consumerGroupName = consumerGroupName; } ​ public String getConsumerTopicTags() { return consumerTopicTags; } ​ public void setConsumerTopicTags(String consumerTopicTags) { this.consumerTopicTags = consumerTopicTags; } ​ } ​

TfmqFactory.java

import java.net.InetAddress;
import java.net.UnknownHostException;
​
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
​
public class TfmqFactory {
    private static final Logger logger = LoggerFactory.getLogger(TfmqFactory.class);
​
    public static DefaultMQProducer newDefaultMQProducer(String producerGroupName, String producerNamesrvAddr) {
        if (producerGroupName == null) {
            logger.info("producerGroupName is null, will not init tfmqClient.producer");
            return null;
        }
        if (producerNamesrvAddr == null) {
            logger.info("producerNamesrvAddr is null, will not init tfmqClient.producer");
            return null;
        }
        DefaultMQProducer producer = new DefaultMQProducer(producerGroupName);
        producer.setNamesrvAddr(producerNamesrvAddr);
        String instanceName = getInstanceName(producerNamesrvAddr);
        // 关键:启动多个实例
        producer.setInstanceName(instanceName);
        logger.info("producer init OK, params[producerGroupName={},producerNamesrvAddr={},instanceName={},]",
                producerGroupName, producerNamesrvAddr, instanceName);
        return producer;
    }
​
    public static DefaultMQPushConsumer newDefaultMQPushConsumer(String consumerGroupName, String consumerNamesrvAddr,
            MessageListenerConcurrently messageListener, String consumerTopicTags) {
        if (consumerGroupName == null) {
            logger.info("consumerGroupName is null, will not init tfmqClient.consumer");
            return null;
        }
        if (consumerNamesrvAddr == null) {
            logger.info("consumerNamesrvAddr is null, will not init tfmqClient.consumer");
            return null;
        }
        if (messageListener == null) {
            logger.info("messageListener is null, will not init tfmqClient.consumer");
            return null;
        }
        if (consumerTopicTags == null) {
            logger.info("consumerTopicTags is null, will not init tfmqClient.consumer");
            return null;
        }
​
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(consumerGroupName);
        consumer.setNamesrvAddr(consumerNamesrvAddr);
        consumer.registerMessageListener(messageListener);
        String instanceName = getInstanceName(consumerNamesrvAddr);
        // 关键:启动多个实例
        consumer.setInstanceName(instanceName);
        try {
            String[] topicTags = consumerTopicTags.split(";");
            for (String topicTag : topicTags) {
                String[] items = topicTag.split(",");
                String topic = items[0];
                String tag = "*";
                if (items.length == 2) {
                    tag = items[1];
                }
                consumer.subscribe(topic, tag);
                logger.info("consumer subscribes topic={}, tag={}", topic, tag);
            }
        } catch (Exception e) {
            logger.error("consumer parse error, consumerTopicTags={}", consumerTopicTags, e);
            return null;
        }
        logger.info("consumer init OK, params[consumerGroupName={},consumerNamesrvAddr={},instanceName={},]",
                consumerGroupName, consumerNamesrvAddr, instanceName);
        return consumer;
    }
​
    private static String getInstanceName(String namesrvAddr) {
        String text = getHostAddress() + namesrvAddr; 
        logger.info("用于生成instanceName的text="+text);
        return MD5Utils.md5(text);
    }
    
    private static String getHostAddress(){
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            logger.error("getHostAddress error", e);
        }
        return "";
    }
}
​

你可能感兴趣的:(RockietMQ实战(自己封装一下))