与消息发送紧密相关的几行代码:
1. DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
2. producer.start();
3. Message msg = new Message(...)
4. SendResult sendResult = producer.send(msg);
5. producer.shutdown();
那这几行代码执行时,背后都做了什么?
一. 首先是DefaultMQProducer.start
@Override publicvoid start()throws MQClientException { this.defaultMQProducerImpl.start(); }
调用了默认生成消息的实现类 -- DefaultMQProducerImpl
调用defaultMQProducerImpl.start()方法,DefaultMQProducerImpl.start()会初始化得到MQClientInstance实例对象,MQClientInstance实例对象调用它自己的start方法会 ,启动一些服务,如拉去消息服务PullMessageService.Start()、启动负载平衡服务RebalanceService.Start(),比如网络通信服务MQClientAPIImpl.Start(), 另外,还会执行与生产消息相关的信息,如注册produceGroup、new一个TopicPublishInfo对象并以默认TopicKey为键值,构成键值对存入DefaultMQProducerImpl的topicPublishInfoTable中。efaultMQProducerImpl.start()后,获取的MQClientInstance实例对象会调用sendHeartbeatToAllBroker()方法,不断向broker发送心跳包,yin'b可以使用下面一幅图大致描述DefaultMQProducerImpl.start()过程:
上图中的三个部分中涉及的内容:
1.1 初始化MQClientInstance
一个客户端只能产生一个MQClientInstance实例对象,产生方式使用了工厂模式与单例模式。MQClientInstance.start()方法启动一些服务,源码如下:
publicvoid start()throws MQClientException {synchronized (this) {switch (this.serviceState) {case CREATE_JUST:this.serviceState = ServiceState.START_FAILED;// If not specified,looking address from name serverif (null ==this.clientConfig.getNamesrvAddr()) {this.mQClientAPIImpl.fetchNameServerAddr(); }// Start request-response channelthis.mQClientAPIImpl.start();// Start various schedule tasksthis.startScheduledTask();// Start pull servicethis.pullMessageService.start();// Start rebalance servicethis.rebalanceService.start();// Start push servicethis.defaultMQProducer.getDefaultMQProducerImpl().start(false); log.info("the client factory [{}] start OK",this.clientId);this.serviceState = ServiceState.RUNNING;break;case RUNNING:break;case SHUTDOWN_ALREADY:break;case START_FAILED:thrownew MQClientException("The Factory object[" +this.getClientId() + "] has been created before, and failed.",null);default:break; } } }
1.2 注册producer
该过程会将这个当前producer对象注册到MQClientInstance实例对象的的producerTable中。一个jvm(一个客户端)中一个producerGroup只能有一个实例,MQClientInstance操作producerTable大概有如下几个方法:
-- selectProducer
-- updateTopicRouteInfoFromNameServer
-- prepareHeartbeatData
-- isNeedUpdateTopicRouteInfo
-- shutdown
注:
根据不同的clientId,MQClientManager将给出不同的MQClientInstance;
根据不同的group,MQClientInstance将给出不同的MQProducer和MQConsumer
1.3 向路由信息表中添加路由
topicPublishInfoTable定义:
publicclass DefaultMQProducerImplimplements MQProducerInner {privatefinal Logger log = ClientLogger.getLog();privatefinal Random random =new Random();privatefinal DefaultMQProducer defaultMQProducer;privatefinal ConcurrentMap