前 言
在深入讲解消息发送之前,我们可先简单概括消息的发送的主要步骤可分为:消息验证、路由查询、选择消息队列、消息组装、消息发送、消息结果处理、异常处理;(单向发送并不处理消息发送结果);同步、异步、单向发送消息的入口API有一些区别,本文将以下面接口实现类为入口分析消息发送的流程:
DefaultMQProducerImpl#sendDefaultImpl
(由于消息发送细节非常多,本文将分析核心步骤,如漏掉还请各位查漏补缺,自行分析哈)
同步发送总结流程图如下:
一、源码分析
DefaultMQProducerImpl#sendDefaultImpl
/**
* 发送信息
* @param msg 消息内容
* @param communicationMode 发送模式
* @param sendCallback 回掉
* @param timeout 超时时间
*/
private SendResult sendDefaultImpl(
Message msg,
final CommunicationMode communicationMode,
final SendCallback sendCallback,
final long timeout
) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
this.makeSureStateOK(); //验证 serviceState == Running 运行中
Validators.checkMessage(msg, this.defaultMQProducer); //1> 验证消息
final long invokeID = random.nextLong();//随机的-invokeId
long beginTimestampFirst = System.currentTimeMillis();//开始时间
long beginTimestampPrev = beginTimestampFirst;
long endTimestamp = beginTimestampFirst;
TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic()); // 2> 获取路由信息
if (topicPublishInfo != null && topicPublishInfo.ok()) {
boolean callTimeout = false;
MessageQueue mq = null;
Exception exception = null;
SendResult sendResult = null;
int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1;//重试次数,同步默认3,其他1次
int times = 0;
String[] brokersSent = new String[timesTotal];//发送的brokerName集合
for (; times < timesTotal; times++) {
String lastBrokerName = null == mq ? null : mq.getBrokerName();
MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName); // 3>选择消息队列
if (mqSelected != null) {
mq = mqSelected;
brokersSent[times] = mq.getBrokerName();
try {
beginTimestampPrev = System.currentTimeMillis();//本次开始时间
long costTime = beginTimestampPrev - beginTimestampFirst;//计算发送消耗时间
if (timeout < costTime) {//如果消耗时间 大于 超时时间,直接break
callTimeout = true;
break;
}
//发送消息
sendResult = this.sendKernelImpl(msg, mq, communicati