DefaultMQProducer是DefaultMQProducerImpl的包装类,开放给开发人员使用,DefaultMQProducer中的几乎所有的方法内部都是由DefaultMQProducerImpl实现的。这个是典型的门面模式设计模式
。
1、DefaultMQProducerImpl
public void start(final boolean startFactory) throws MQClientException {
switch (this.serviceState) {
case CREATE_JUST:
this.serviceState = ServiceState.START_FAILED;
this.checkConfig();
if (!this.defaultMQProducer.getProducerGroup().equals(MixAll.CLIENT_INNER_PRODUCER_GROUP)) {
this.defaultMQProducer.changeInstanceNameToPID();
}
//#1 创建 MQClientInstance
this.mQClientFactory = MQClientManager.getInstance().getOrCreateMQClientInstance(this.defaultMQProducer, rpcHook);
//#2 MQClientInstance#producerTable
boolean registerOK = mQClientFactory.registerProducer(this.defaultMQProducer.getProducerGroup(), this);
this.topicPublishInfoTable.put(this.defaultMQProducer.getCreateTopicKey(), new TopicPublishInfo());
if (startFactory) {
mQClientFactory.start();
}
this.defaultMQProducer.isSendMessageWithVIPChannel());
this.serviceState = ServiceState.RUNNING;
break;
...
}
this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();//#3
this.timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
RequestFutureTable.scanExpiredRequest();
}
}, 1000 * 3, 1000);
}
步骤3:主要是生产者、消费者实例与broker集群建立通信,通过心跳包定时注册、监控彼此的健康状态信息。
2、MQClientManager
public class MQClientManager {
private static MQClientManager instance = new MQClientManager();
private ConcurrentMap<String, MQClientInstance> factoryTable = new ConcurrentHashMap<String, MQClientInstance>();
public MQClientInstance getOrCreateMQClientInstance(final ClientConfig clientConfig, RPCHook rpcHook) {
String clientId = clientConfig.buildMQClientId();
MQClientInstance instance = this.factoryTable.get(clientId);
if (null == instance) {
instance =
new MQClientInstance(clientConfig.cloneClientConfig(),
this.factoryIndexGenerator.getAndIncrement(), clientId, rpcHook);
MQClientInstance prev = this.factoryTable.putIfAbsent(clientId, instance);
}
return instance;
}
}
该类的作用是创建MQClientInstance实例。MQClientManager是静态变量,全局应该唯一一份。
前提条件:生产者实例DefaultMQProducerImpl
、消费者实例DefaultMQPushConsumerImpl
对应同一实例。则启动过程中都会涉及MQClientInstance
实例的创建,并且监听同一个topic的consumer、producer共享同一个MQClientInstance,也即其对应的ClientId
[ip:port:unitName]必须一样,这样的结果就是MQClientInstance#start方法中核心功能在consumer、producer启动过程中通过serviceState字段控制后只会被初始化一次。
2.1、MQClientInstance
public void start() throws MQClientException {
synchronized (this) {
switch (this.serviceState) {
case CREATE_JUST:
this.serviceState = ServiceState.START_FAILED;
// If not specified,looking address from name server
if (null == this.clientConfig.getNamesrvAddr()) {
this.mQClientAPIImpl.fetchNameServerAddr();
}
// Start request-response channel
this.mQClientAPIImpl.start();//#1 启动netty RPC功能
// Start various schedule tasks
this.startScheduledTask();//#2 开启各种定时任务
// Start pull service
this.pullMessageService.start();//#3 开启从broker端拉取消息的任务
// Start rebalance service
//#4 开启消费者实例分配队列的任务,从 consumerTable 中获取全部消费者实例,根据指定的分配策略调整消费者实例监听的队列
this.rebalanceService.start();
// Start push service
this.defaultMQProducer.getDefaultMQProducerImpl().start(false);// 调用DefaultMQProducerImpl#start
this.serviceState = ServiceState.RUNNING;
break;
case START_FAILED:
default:
break;
}
}
}
- 步骤2涉及的定时任务包括:fetchNameServerAddr、updateTopicRouteInfoFromNameServer、sendHeartbeatToAllBrokerWithLock、persistAllConsumerOffset、adjustThreadPool等。
- 步骤3、4中任务类之抽象类ServiceThread,其涉及的子类包括FileWatchService、PullMessageService、RebalanceService。
- PullMessageService:不断轮询
ProcessQueue
,从ProcessQueue队列中获取消息,最终通过回调方式投递到服务自定义的消费着监听器中。 - RebalanceService:主要是通过分配策略给当前消费组下的消费实例分配监听的队列信息。