1.消费者启动流程
@Override
public void start ( ) throws MQClientException {
setConsumerGroup ( NamespaceUtil. wrapNamespace ( this . getNamespace ( ) , this . consumerGroup) ) ;
this . defaultMQPushConsumerImpl. start ( ) ;
}
public synchronized void start ( ) throws MQClientException {
switch ( this . serviceState) {
case CREATE_JUST:
log. info ( "the consumer [{}] start beginning. messageModel={}, isUnitMode={}" , this . defaultMQPushConsumer. getConsumerGroup ( ) ,
this . defaultMQPushConsumer. getMessageModel ( ) , this . defaultMQPushConsumer. isUnitMode ( ) ) ;
this . serviceState = ServiceState. START_FAILED;
this . checkConfig ( ) ;
this . copySubscription ( ) ;
if ( this . defaultMQPushConsumer. getMessageModel ( ) == MessageModel. CLUSTERING) {
this . defaultMQPushConsumer. changeInstanceNameToPID ( ) ;
}
this . mQClientFactory = MQClientManager. getInstance ( ) . getOrCreateMQClientInstance ( this . defaultMQPushConsumer, this . rpcHook) ;
this . rebalanceImpl. setConsumerGroup ( this . defaultMQPushConsumer. getConsumerGroup ( ) ) ;
this . rebalanceImpl. setMessageModel ( this . defaultMQPushConsumer. getMessageModel ( ) ) ;
this . rebalanceImpl. setAllocateMessageQueueStrategy ( this . defaultMQPushConsumer. getAllocateMessageQueueStrategy ( ) ) ;
this . rebalanceImpl. setmQClientFactory ( this . mQClientFactory) ;
this . pullAPIWrapper = new PullAPIWrapper (
mQClientFactory,
this . defaultMQPushConsumer. getConsumerGroup ( ) , isUnitMode ( ) ) ;
this . pullAPIWrapper. registerFilterMessageHook ( filterMessageHookList) ;
if ( this . defaultMQPushConsumer. getOffsetStore ( ) != null) {
this . offsetStore = this . defaultMQPushConsumer. getOffsetStore ( ) ;
} else {
switch ( this . defaultMQPushConsumer. getMessageModel ( ) ) {
case BROADCASTING:
this . offsetStore = new LocalFileOffsetStore ( this . mQClientFactory, this . defaultMQPushConsumer. getConsumerGroup ( ) ) ;
break ;
case CLUSTERING:
this . offsetStore = new RemoteBrokerOffsetStore ( this . mQClientFactory, this . defaultMQPushConsumer. getConsumerGroup ( ) ) ;
break ;
default :
break ;
}
this . defaultMQPushConsumer. setOffsetStore ( this . offsetStore) ;
}
this . offsetStore. load ( ) ;
if ( this . getMessageListenerInner ( ) instanceof MessageListenerOrderly ) {
this . consumeOrderly = true ;
this . consumeMessageService =
new ConsumeMessageOrderlyService ( this , ( MessageListenerOrderly) this . getMessageListenerInner ( ) ) ;
} else if ( this . getMessageListenerInner ( ) instanceof MessageListenerConcurrently ) {
this . consumeOrderly = false ;
this . consumeMessageService =
new ConsumeMessageConcurrentlyService ( this , ( MessageListenerConcurrently) this . getMessageListenerInner ( ) ) ;
}
this . consumeMessageService. start ( ) ;
boolean registerOK = mQClientFactory. registerConsumer ( this . defaultMQPushConsumer. getConsumerGroup ( ) , this ) ;
if ( ! registerOK) {
this . serviceState = ServiceState. CREATE_JUST;
this . consumeMessageService. shutdown ( ) ;
throw new MQClientException ( "The consumer group[" + this . defaultMQPushConsumer. getConsumerGroup ( )
+ "] has been created before, specify another name please." + FAQUrl. suggestTodo ( FAQUrl. GROUP_NAME_DUPLICATE_URL) ,
null) ;
}
mQClientFactory. start ( ) ;
log. info ( "the consumer [{}] start OK." , this . defaultMQPushConsumer. getConsumerGroup ( ) ) ;
this . serviceState = ServiceState. RUNNING;
break ;
case RUNNING:
case START_FAILED:
case SHUTDOWN_ALREADY:
throw new MQClientException ( "The PushConsumer service state not OK, maybe started once, "
+ this . serviceState
+ FAQUrl. suggestTodo ( FAQUrl. CLIENT_SERVICE_NOT_OK) ,
null) ;
default :
break ;
}
this . updateTopicSubscribeInfoWhenSubscriptionChanged ( ) ;
this . mQClientFactory. checkClientInBroker ( ) ;
this . mQClientFactory. sendHeartbeatToAllBrokerWithLock ( ) ;
this . mQClientFactory. rebalanceImmediately ( ) ;
}
private void copySubscription ( ) throws MQClientException {
try {
Map< String, String> sub = this . defaultMQPushConsumer. getSubscription ( ) ;
if ( sub != null) {
for ( final Map. Entry< String, String> entry : sub. entrySet ( ) ) {
final String topic = entry. getKey ( ) ;
final String subString = entry. getValue ( ) ;
SubscriptionData subscriptionData = FilterAPI. buildSubscriptionData ( this . defaultMQPushConsumer. getConsumerGroup ( ) ,
topic, subString) ;
this . rebalanceImpl. getSubscriptionInner ( ) . put ( topic, subscriptionData) ;
}
}
if ( null == this . messageListenerInner) {
this . messageListenerInner = this . defaultMQPushConsumer. getMessageListener ( ) ;
}
switch ( this . defaultMQPushConsumer. getMessageModel ( ) ) {
case BROADCASTING:
break ;
case CLUSTERING:
final String retryTopic = MixAll. getRetryTopic ( this . defaultMQPushConsumer. getConsumerGroup ( ) ) ;
SubscriptionData subscriptionData = FilterAPI. buildSubscriptionData ( this . defaultMQPushConsumer. getConsumerGroup ( ) ,
retryTopic, SubscriptionData. SUB_ALL) ;
this . rebalanceImpl. getSubscriptionInner ( ) . put ( retryTopic, subscriptionData) ;
break ;
default :
break ;
}
} catch ( Exception e) {
throw new MQClientException ( "subscription exception" , e) ;
}
}
构建主题订阅信息 SubscriptionData 并加入到 Rebalancelmpl 的订阅消息中 通过调用 DefaultMQPushConsumerlmpl#subscrib巳( String topic, String subExpression) 方法, 订阅重试主题消息 , RocketMQ 消息重试是以消费组为单位,而不是主题,消息重试主题名为 %RETRY%+消费组名. 消费者在启动的时候会自动订阅该主题,参与该主题的消息队列负载
if ( this . defaultMQPushConsumer. getMessageModel ( ) == MessageModel. CLUSTERING) {
this . defaultMQPushConsumer. changeInstanceNameToPID ( ) ;
}
this . mQClientFactory = MQClientManager. getInstance ( ) . getOrCreateMQClientInstance ( this . defaultMQPushConsumer, this . rpcHook) ;
this . rebalanceImpl. setConsumerGroup ( this . defaultMQPushConsumer. getConsumerGroup ( ) ) ;
this . rebalanceImpl. setMessageModel ( this . defaultMQPushConsumer. getMessageModel ( ) ) ;
this . rebalanceImpl. setAllocateMessageQueueStrategy ( this . defaultMQPushConsumer. getAllocateMessageQueueStrategy ( ) ) ;
this . rebalanceImpl. setmQClientFactory ( this . mQClientFactory) ;
this . pullAPIWrapper = new PullAPIWrapper (
mQClientFactory,
this . defaultMQPushConsumer. getConsumerGroup ( ) , isUnitMode ( ) ) ;
this . pullAPIWrapper. registerFilterMessageHook ( filterMessageHookList) ;
初始化 MQC!ientlnstance Rebalancelmple (消息重新负载实现类)
if ( this . defaultMQPushConsumer. getOffsetStore ( ) != null) {
this . offsetStore = this . defaultMQPushConsumer. getOffsetStore ( ) ;
} else {
switch ( this . defaultMQPushConsumer. getMessageModel ( ) ) {
case BROADCASTING:
this . offsetStore = new LocalFileOffsetStore ( this . mQClientFactory, this . defaultMQPushConsumer. getConsumerGroup ( ) ) ;
break ;
case CLUSTERING:
this . offsetStore = new RemoteBrokerOffsetStore ( this . mQClientFactory, this . defaultMQPushConsumer. getConsumerGroup ( ) ) ;
break ;
default :
break ;
}
this . defaultMQPushConsumer. setOffsetStore ( this . offsetStore) ;
}
this . offsetStore. load ( ) ;
初始化消息进度, 如果消息消费是集群模式,那么消息进度保存在 Broker 上;如果是广播模式,那么消息进度存储在消费端
if ( this . getMessageListenerInner ( ) instanceof MessageListenerOrderly ) {
this . consumeOrderly = true ;
this . consumeMessageService =
new ConsumeMessageOrderlyService ( this , ( MessageListenerOrderly) this . getMessageListenerInner ( ) ) ;
} else if ( this . getMessageListenerInner ( ) instanceof MessageListenerConcurrently ) {
this . consumeOrderly = false ;
this . consumeMessageService =
new ConsumeMessageConcurrentlyService ( this , ( MessageListenerConcurrently) this . getMessageListenerInner ( ) ) ;
}
this . consumeMessageService. start ( ) ;
根据是否是顺序消费,创建消费端消费线程服务 ConsumeMessageService.负责消息消费,内部维护一个线程池
boolean registerOK = mQClientFactory. registerConsumer ( this . defaultMQPushConsumer. getConsumerGroup ( ) , this ) ;
if ( ! registerOK) {
this . serviceState = ServiceState. CREATE_JUST;
this . consumeMessageService. shutdown ( ) ;
throw new MQClientException ( "The consumer group[" + this . defaultMQPushConsumer. getConsumerGroup ( )
+ "] has been created before, specify another name please." + FAQUrl. suggestTodo ( FAQUrl. GROUP_NAME_DUPLICATE_URL) ,
null) ;
}
mQClientFactory. start ( ) ;
向 MQClientlnstance 注册消费者,并启动 MQClientlnstance 在一个 JVM 中的所有消费者、生产者持有同一个 MQClientlnstance, MQClientlnstance 只会启动一次