通过上一篇demo,发送消息关键方法为:DefaultMQProducer.send()方法
通过send()方法,进入到内部关键代码,sendDefaultImpl();
方法有点长,我们先通过一个时序图,简单看一下方法的大致流程
接下来,对图中重点的方法进行解析:
1、tryToFindTopicPublishInfo(),获取主题的队列配置
该方法主要是获取主题的队列信息,当从本地内存中,获取不到时,从namesrv服务器获取主题配置信息
诶,问题来了,为什么要从namesrv服务器获取呢
这就要说说namesrv和broker了
broker:主要是做消息存储的
rocketmq作为消息中间件,肯定需要有高可用的保障策略,自然而然就引入了集群,由集群就能联想到 主从、双主、双从
在多个broker集群情况下,则需要一个中心来管理broker。
代码如下:
//获取主题的配置信息
private TopicPublishInfo tryToFindTopicPublishInfo(final String topic) {
//1.topicPublishInfoTable相当于一层缓存,保存了topic的队列配置信息
TopicPublishInfo topicPublishInfo = this.topicPublishInfoTable.get(topic);
if (null == topicPublishInfo || !topicPublishInfo.ok()) {
//2.当topicPublishInfoTable中没有时,从namesrv服务器获取主题的队列配置信息
this.topicPublishInfoTable.putIfAbsent(topic, new TopicPublishInfo());
this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic);
topicPublishInfo = this.topicPublishInfoTable.get(topic);
}
if (topicPublishInfo.isHaveTopicRouterInfo() || (topicPublishInfo != null && topicPublishInfo.ok())) {
return topicPublishInfo;
}
else {
this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic, true, this.defaultMQProducer);
topicPublishInfo = this.topicPublishInfoTable.get(topic);
return topicPublishInfo;
}
}
2、selectOneMessageQueue(),选择主题的一个队列
该方法主要是选择主题的一个队列发送消息,选择的策略是怎么样的呢?通过代码可得知,是通过AtomaticInteger顺序轮询获取,这样就保证消息里面多个队列的消息几乎是均衡的。
哦,对了,队列是什么呢?
rocketmq将主题分成多个队列,通过多个队列实现消费端的负载均衡、顺序消费等巴拉巴拉很多功能。
上代码:
//选择一个消息队列,发送消息
public MessageQueue selectOneMessageQueue(final String lastBrokerName) {
if (lastBrokerName != null) {
//AtomicInteger sendWhichQueue = new AtomicInteger(0);
//sendSwitchQueue为自增的
int index = this.sendWhichQueue.getAndIncrement();
//发送时,轮询主题的消息队列,保障消息队列的均衡
for (int i = 0; i < this.messageQueueList.size(); i++) {
int pos = Math.abs(index++) % this.messageQueueList.size();
MessageQueue mq = this.messageQueueList.get(pos);
if (!mq.getBrokerName().equals(lastBrokerName)) {
return mq;
}
}
return null;
}
else {
int index = this.sendWhichQueue.getAndIncrement();
int pos = Math.abs(index) % this.messageQueueList.size();
return this.messageQueueList.get(pos);
}
}
3、sendKenelImpl(),终于到发送消息的核心代码了
该方法主要是封装消息内容,通过netty向服务端发送请求。
具体是怎么和服务端通信的,在《rocketmq源代码学习----客户端服务端通信》一章中再去详细说明。