rocketmq-如何发送消息?

311 阅读3分钟

前言

本文主要讲怎么应用rocketmq发送消息。

mq客户端核心类-DefaultMQProducer

核心方法

@Override
public SendResult send(Message msg) throws MQClientException, RemotingException, MQBrokerException,
        InterruptedException {
    return this.defaultMQProducerImpl.send(msg);
}

接口的各种发送消息的方法

image.png

默认实现类

image.png

类继承图

image.png

封装mq客户端的核心类

自己再封装一下,写个发送消息工具类,或者干脆搞到一个小的jar里去。

源码实现

package xxx.rocketmq;

import xxx.util.LogUtil;

import com.alibaba.rocketmq.client.exception.MQBrokerException;
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;
import com.alibaba.rocketmq.remoting.exception.RemotingException;

/**
 * 生产者,初始化MQProducer
 */
public class Producer {
 private String namesrvAddr; //ip
 private String producerGroup; //group
 private DefaultMQProducer producer; //官方自带默认实现

 public String getNamesrvAddr() {
  return namesrvAddr;
 }

 public void setNamesrvAddr(String namesrvAddr) {
  this.namesrvAddr = namesrvAddr;
 }

 public String getProducerGroup() {
  return producerGroup;
 }

 public void setProducerGroup(String producerGroup) {
  this.producerGroup = producerGroup;
 }

//初始化
 public void init() {
  LogUtil.INFOLOG.info("RocketMQ-Producer初始化参数开始");
  LogUtil.INFOLOG.info("producerGroup: " + producerGroup);
  producer = new DefaultMQProducer(producerGroup);
  producer.setNamesrvAddr(namesrvAddr);
  // 定义实例名称,不适用默认.
  producer.setInstanceName(Long.toString(System.currentTimeMillis()));
  // Message Body大小超过阀值,则压缩,默认是1024 * 4
  producer.setCompressMsgBodyOverHowmuch(Integer.MAX_VALUE);
  try {
//启动生产者
   producer.start();
  } catch (Exception e) {
   LogUtil.INFOLOG.error("RocketMQ-Producer初始化参数异常:", e);
  }
 }

 public void destroy() {
  producer.shutdown();
 }

 /**
  * 发送消息
  * 
  * @param message
  * @return
  */
 public SendResult send(Message message) throws InterruptedException,
   RemotingException, MQClientException, MQBrokerException {
//调用官方默认实现发送消息
  SendResult result = producer.send(message);
  return result;
 }

}

定义bean

<!-- 扫码 -->
 <bean id="mqProducer_xxx" class="xxx.rocketmq.Producer" init-method="init" destroy-method="destroy">
    <property name="namesrvAddr" value="${namesrvAddr}"/>
    <property name="producerGroup" value="${rocketmq.xxx.group}"/>
</bean>

应用层

应用层工具类

应用项目里再简单封装一下,加了topic功能。

定义bean

<bean id="sendMqProcess_xxx" class="xxx.trade.process.SendMqProcess">
    <property name="producer" ref="mqProducer_xxx"/>
    <property name="topic" value="${rocketmq.xxx.topic}"/>
    <property name="subExpression" value="${rocketmq.xxx.subExpression}"/>
</bean>

源码实现

package xxx.trade.process;

import xxx.core.exception.BizException;
import xxx.rocketmq.Producer;
import xxx.trade.constant.xxxReturnCode;
import xxx.trade.util.LogUtil;

import com.alibaba.rocketmq.client.producer.SendResult;
import com.alibaba.rocketmq.client.producer.SendStatus;
import com.alibaba.rocketmq.common.message.Message;

public class SendMqProcess {

 private Producer producer;

 private String topic;

 private String subExpression;

 /**
  * 发送mq消息
  * 
  * @param jsonMsgContent
  *            消息内容,必须是json格式
  * @return
  * @throws BizException
  * @see
  */
 public SendStatus sendMqMessage(String jsonMsgContent) throws BizException {
  try {
   Message msg = new Message(topic, subExpression,
     (jsonMsgContent).getBytes("UTF-8"));
   SendResult sendResult = producer.send(msg);
   LogUtil.INFOLOG.info("消息内容:" + jsonMsgContent + "\n返回结果:"
     + sendResult.toString());
   return sendResult.getSendStatus();
  } catch (Exception e) {
   throw new BizException(xxxReturnCode.DEAL_EXCEPTION.getCode(),
     xxxReturnCode.DEAL_EXCEPTION
       .getDesc("Producer send message 异常:"
         + jsonMsgContent)
       + e);
  }
 }

 public void setProducer(Producer producer) {
  this.producer = producer;
 }

 public void setTopic(String topic) {
  this.topic = topic;
 }

 public void setSubExpression(String subExpression) {
  this.subExpression = subExpression;
 }

}

应用层提供静态方法发送消息

提供类的静态方法,方便使用。

public class xxxMerchantNotifyManager {
private static final SendMqProcess SENDMQPROCESS_xxx = (SendMqProcess) SpringContext
            .getService("sendMqProcess_xxx");

// 异步线程发送消息到MQ
public static void sendMqMessage(final BackMethodParm backMethodParm,
  final Orderbill orderbill, final boolean ignore) {

 Runnable childThread = new Runnable() {
  @Override
  public void run() {
   boolean isSentOk = false;

   String xxx = orderbill.getxxx();
   try {
    // 参数处理
    String json = convertJSONString(backMethodParm, ignore);
    try {
     // 发送消息队列
     LogUtil.INFOLOG.info("sendMqMessage消息内容:" + json);
     SendStatus state = SENDMQPROCESS_QRCODE
       .sendMqMessage(json);
     LogUtil.INFOLOG.info("sendMqMessage返回内容:" + state.toString());
     if (state == SendStatus.SEND_OK
       || state == SendStatus.FLUSH_DISK_TIMEOUT
       || state == SendStatus.FLUSH_SLAVE_TIMEOUT
       || state == SendStatus.SLAVE_NOT_AVAILABLE) {
      isSentOk = true;
     }
    } catch (BizException e) {
     log.error(LogConst.THROWABLEEXCEPTIONS + xxx
       + "异步通知发送异常", e);
    } catch (Exception e) {
     log.error(LogConst.THROWABLEEXCEPTIONS + xxx
       + "异步通知发送异常", e);
    }
   } catch (Exception ex) {
    log.error(LogConst.THROWABLEEXCEPTIONS + xxx
      + "异步通知发送json转对象发生异常", ex);
   }

   // MQ发送失败进入容错处理
   if (!isSentOk) {
    try {
     NotifyFault entity = content2NotifyFault(orderbill,
       backMethodParm);
     log.info(LogConst.THROWABLEEXCEPTIONS + xxx
       + "异步通知发送:" + entity);
     ServiceDeclare.notifyFaultService
       .insertNotifyFault(entity);
    } catch (Exception e) {
     log.error(LogConst.THROWABLEEXCEPTIONS + xxx
       + "异步通知消息转容错处理发生异常", e);
    }
   }
  }
 };
 try {
  threadPool.execute(childThread);
 } catch (Throwable t) {
  log.error(LogConst.THROWABLEEXCEPTIONS + "mq消息处理异常:", t);
 }
}

调用静态方法发送消息

xxxMerchantNotifyManager.sendMqMessage();

总结

大致的思路就是,基于mq客户端官方自带的默认实现去发送消息,然后自己也可以封装一下,甚至可以封装多层,每一层的封装,其实就是对于特殊情况多加了一点内容。如果是测试使用,其实直接调用官方默认实现发送消息即可。只不过生产环境,一般都会封装一层,甚至多层。