简单使用
public class SyncProducer {
public static void main(String[] args) throws Exception {
//使用ProducerGroup初始化Producer
DefaultMQProducer producer = new
DefaultMQProducer("group");
// 指定namesrv
producer.setNamesrvAddr("localhost:9876");
producer.start();
for (int i = 0; i < 100; i++) {
//创建消息
Message msg = new Message("Topic" /* Topic */,
"TagA" /* Tag */,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
);
//发送消息
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
}
//关闭Producer
producer.shutdown();
}
}
上面是同步发送消息的简单使用,主要是初始化DefaultMQProducer,调用start()方法和send()方法.接下来具体分析生产者发送消息的具体过程。
DefaultMQProducer
DefaultMQProducer就是消息生产者的客户端,DefaultMQProducer的定义如下:
public class DefaultMQProducer extends ClientConfig implements MQProducer {
...
}
可以看到DefaultMQProducer实现了MQProducer接口并继承了ClientConfig类。
- MQProducer接口
在MQProducer接口定义了Producer的一些操作,并且继承了MQAdmin,在MQAdmin主要是一些管理功能接口,MQProducer中定义了各种发送消息的结构,同步发送,异步发送,oneway发送,批量发送和事务消息的发送。
public interface MQProducer extends MQAdmin {
void start() throws MQClientException;
void shutdown();
List<MessageQueue> fetchPublishMessageQueues(final String topic) throws MQClientException;
SendResult send(final Message msg) throws MQClientException, RemotingException, MQBrokerException,
InterruptedException;
// 省略一系列send方法
// 失误相关的发送消息
TransactionSendResult sendMessageInTransaction(final Message msg,
final LocalTransactionExecuter tranExecuter, final Object arg) throws MQClientException;
TransactionSendResult sendMessageInTransaction(final Message msg,
final Object arg) throws MQClientException;
//for batch
SendResult send(final Collection<Message> msgs) throws MQClientException, RemotingException, MQBrokerException,
InterruptedException;
// 省略一系列的batch send的方法
}
public interface MQAdmin {
void createTopic(final String key, final String newTopic, final int queueNum)
throws MQClientException;
void createTopic(String key, String newTopic, int queueNum, int topicSysFlag)
throws MQClientException;
long searchOffset(final MessageQueue mq, final long timestamp) throws MQClientException;
long maxOffset(final MessageQueue mq) throws MQClientException;
long minOffset(final MessageQueue mq) throws MQClientException;
long earliestMsgStoreTime(final MessageQueue mq) throws MQClientException;
MessageExt viewMessage(final String offsetMsgId) throws RemotingException, MQBrokerException,
InterruptedException, MQClientException;
QueryResult queryMessage(final String topic, final String key, final int maxNum, final long begin,
final long end) throws MQClientException, InterruptedException;
MessageExt viewMessage(String topic,
String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException;
}
- ClientConfig类
ClientConfig根据类名称大概也能猜到,主要是负责一些配置信息。
public class ClientConfig {
public static final String SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY = "com.rocketmq.sendMessageWithVIPChannel";
private String namesrvAddr = NameServerAddressUtils.getNameServerAddresses();
private String clientIP = RemotingUtil.getLocalAddress();
private String instanceName = System.getProperty("rocketmq.client.name", "DEFAULT");
private int clientCallbackExecutorThreads = Runtime.getRuntime().availableProcessors();
protected String namespace;
protected AccessChannel accessChannel = AccessChannel.LOCAL;
private int pollNameServerInterval = 1000 * 30;
private int heartbeatBrokerInterval = 1000 * 30;
private int persistConsumerOffsetInterval = 1000 * 5;
private boolean unitMode = false;
private String unitName;
private boolean vipChannelEnabled = Boolean.parseBoolean(System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false"));
private boolean useTLS = TlsSystemConfig.tlsEnable;
private LanguageCode language = LanguageCode.JAVA;
}
大致了解了一下DefaultMQProducer的结构,DefaultMQProducer有两个核心方法start()、send()方法。
start()
DefaultMQProducer初始化完成后,会调用start()方法,start方法主要是负责建立网络通信、初始化配置。它的具体实现最终是交给defaultMQProducerImpl#start()方法了。
public void start(final boolean startFactory) throws MQClientException {
// 根据serviceState处理不同逻辑,初始化都是CREATE_JUST
switch (this.serviceState) {
case CREATE_JUST:
this.serviceState = ServiceState.START_FAILED;
// 检查配置信息,主要是ProducerGroup的,不重要
this.checkConfig();
// 判断ProducerGroup是否是CLIENT_INNER_PRODUCER_GROUP,如果是将 ClientConfig#instanceName 改为进程PID,什么情况下是CLIENT_INNER_PRODUCER_GROUP呢?接下来会接触到,由于我们都会指定自己的group,所以这里会进入到if语句里面修改ClientConfig#instanceName为进程PID
if (!this.defaultMQProducer.getProducerGroup().equals(MixAll.CLIENT_INNER_PRODUCER_GROUP)) {
this.defaultMQProducer.changeInstanceNameToPID();
}
// 创建一个MQClientInstance,这个是重点,就是它完成了和broker的通信
// 创建完成后MQClientManager会保存ClientId -> MQClientInstance的映射
this.mQClientFactory = MQClientManager.getInstance().getAndCreateMQClientInstance(this.defaultMQProducer, rpcHook);
// 注册Producer,就是将 ProducerGroup -> DefaultMQProducerImpl 的关系保存到MQClientInstance中
boolean registerOK = mQClientFactory.registerProducer(this.defaultMQProducer.getProducerGroup(), this);
if (!registerOK) {
// 如果注册失败,抛异常结束,终止启动
}
// topicPublishInfoTable 初始化一个topic的路由信息,这个CreateTopicKey就是MixAll.AUTO_CREATE_TOPIC_KEY_TOPIC,这个topic和Broker的AutoCreateTopicEnable进行配置使用,后面会详细介绍
this.topicPublishInfoTable.put(this.defaultMQProducer.getCreateTopicKey(), new TopicPublishInfo());
// startFactory这时是true,所以会调用MQClientInstance的start()方法
if (startFactory) {
mQClientFactory.start();
}
log.info("the producer [{}] start OK. se