一般创建AliMQ(RocketMQ)的Consumer的方式都是如下:
AliMQHandler.buildConsumer(accessKey, secretKey,
systemCancelOrder.get("topicId"),
"CANCEL_ORDER"+"||"+systemCancelOrder.get("tagPolicy"), // systemCancelOrder.get("tag"),
systemCancelOrder.get("consumerId"),
systemCancelOrderListener);
里面如下:
public static Consumer buildConsumer(
String accessKey, String secretKey,
String topicId, String tag, String consumerId,
MessageListener messageListener) {
Properties properties = new Properties();
properties.put("ConsumerId", consumerId);
properties.put("AccessKey", accessKey);
properties.put("SecretKey", secretKey);
Consumer mqConsumer = ONSFactory.createConsumer(properties);
mqConsumer.subscribe(topicId, tag, messageListener);
mqConsumer.start();
return mqConsumer;
}
可以看到真正执行的是下面三个方法,至于创建mq的原理是什么,里面是怎么实现的呢,一起看下。
Consumer mqConsumer = ONSFactory.createConsumer(properties);
在这个方法中创建了consumer,实则是用Properties创建了一个新的Consumer。
public ConsumerImpl(final Properties properties) {
super(properties);
boolean postSubscriptionWhenPull = Boolean.parseBoolean(properties.getProperty(PropertyKeyConst.PostSubscriptionWhenPull, "false"));
this.defaultMQPushConsumer.setPostSubscriptionWhenPull(postSubscriptionWhenPull);
String messageModel = properties.getProperty(PropertyKeyConst.MessageModel, PropertyValueConst.CLUSTERING);
this.defaultMQPushConsumer.setMessageModel(MessageModel.valueOf(messageModel));
}
这个方法中先调用了父类ONSConsumerAbstract中的构造方法,在ONSConsumerAbstract的构造方法中又调用了ONSClientAbstract的构造方法。
this.sessionCredentials.updateContent(properties);
然后检测参数有效性。
// 用户指定了Name Server
// 私有云模式有可能需要
this.nameServerAddr = this.properties.getProperty(PropertyKeyConst.NAMESRV_ADDR);
if (nameServerAddr != null) {
return;
}
this.nameServerAddr = fetchNameServerAddr();
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
public void run() {
try {
String nsAddrs = fetchNameServerAddr();
if (nsAddrs != null && !ONSClientAbstract.this.nameServerAddr.equals(nsAddrs)) {
ONSClientAbstract.this.nameServerAddr = nsAddrs;
if (isStarted()) {
updateNameServerAddr(nsAddrs);
}
}
} catch (Exception e) {
log.error("update name server periodically failed.", e);
}
}
}, 10 * 1000L, 30 * 1000L, TimeUnit.MILLISECONDS);
this.defaultMQPushConsumer = new DefaultMQPushConsumer(new OnsClientRPCHook(sessionCredentials));
在创建consumer的时候创建了一个钩子,用于填写与broker连接前的校验参数。
consumer中有许多参数,包括客户端ip,消费的策略(默认是CONSUME_FROM_LAST_OFFSET)等。
boolean isVipChannelEnabled = Boolean.parseBoolean(properties.getProperty(PropertyKeyConst.isVipChannelEnabled, "false"));
this.defaultMQPushConsumer.setVipChannelEnabled(isVipChannelEnabled);
this.defaultMQPushConsumer.setConsumerGroup(consumerGroup);
String instanceName = properties.getProperty(PropertyKeyConst.InstanceName, this.buildIntanceName());
this.defaultMQPushConsumer.setInstanceName(instanceName);
this.defaultMQPushConsumer.setNamesrvAddr(this.getNameServerAddr());
String consumeThreadNums = properties.getProperty(PropertyKeyConst.ConsumeThreadNums);
if (!UtilAll.isBlank(consumeThreadNums)) {
this.defaultMQPushConsumer.setConsumeThreadMin(Integer.valueOf(consumeThreadNums));
this.defaultMQPushConsumer.setConsumeThreadMax(Integer.valueOf(consumeThreadNums));
}
String configuredCachedMessageAmount = properties.getProperty(PropertyKeyConst.MaxCachedMessageAmount);
if (!UtilAll.isBlank(configuredCachedMessageAmount)) {
maxCachedMessageAmount = Math.min(MAX_CACHED_MESSAGE_AMOUNT, Integer.valueOf(configuredCachedMessageAmount));
maxCachedMessageAmount = Math.max(MIN_CACHED_MESSAGE_AMOUNT, maxCachedMessageAmount);
this.defaultMQPushConsumer.setPullThresholdForTopic(maxCachedMessageAmount);
}
String configuredCachedMessageSizeInMiB = properties.getProperty(PropertyKeyConst.MaxCachedMessageSizeInMiB);
if (!UtilAll.isBlank(configuredCachedMessageSizeInMiB)) {
maxCachedMessageSizeInMiB = Math.min(MAX_CACHED_MESSAGE_SIZE_IN_MIB, Integer.valueOf(configuredCachedMessageSizeInMiB));
maxCachedMessageSizeInMiB = Math.max(MIN_CACHED_MESSAGE_SIZE_IN_MIB, maxCachedMessageSizeInMiB);
this.defaultMQPushConsumer.setPullThresholdSizeForTopic(maxCachedMessageSizeInMiB);
}
包括是否走vipChannel,为什么叫做vip通道呢?因为rocketmq监听的这个端口的消息少一点,特别是存储消息到磁盘的那块逻辑,vip通道是不会做的。所以个人觉得这个通道响应速度会快点。
设置consumerGroup,实例名称,nameServer地址,消费者线程的最小和最大线程数,包括一些在PropertyKeyConst类中的配置(客户端缓存消息数量,客户端缓存最大内容)。
// 为Consumer增加消息轨迹回发模块
String msgTraceSwitch = properties.getProperty(PropertyKeyConst.MsgTraceSwitch);
if (!UtilAll.isBlank(msgTraceSwitch) && (!Boolean.parseBoolean(msgTraceSwitch))) {
log.info("MQ Client Disable the Trace Hook!");
} else {
try {
Properties tempProperties = new Properties();
tempProperties.put(OnsTraceConstants.AccessKey, sessionCredentials.getAccessKey());
tempProperties.put(OnsTraceConstants.SecretKey, sessionCredentials.getSecretKey());
tempProperties.put(OnsTraceConstants.MaxMsgSize, "128000");
tempProperties.put(OnsTraceConstants.AsyncBufferSize, "2048");
tempProperties.put(OnsTraceConstants.MaxBatchNum, "100");
tempProperties.put(OnsTraceConstants.NAMESRV_ADDR, this.getNameServerAddr());
tempProperties.put(OnsTraceConstants.InstanceName, "PID_CLIENT_INNER_TRACE_PRODUCER");
tempProperties.put(OnsTraceConstants.TraceDispatcherType, OnsTraceDispatcherType.CONSUMER.name());
AsyncArrayDispatcher dispatcher = new AsyncArrayDispatcher(tempProperties, sessionCredentials);
dispatcher.setHostConsumer(defaultMQPushConsumer.getDefaultMQPushConsumerImpl());
traceDispatcher = dispatcher;
this.defaultMQPushConsumer.getDefaultMQPushConsumerImpl().registerConsumeMessageHook(
new OnsConsumeMessageHookImpl(traceDispatcher));
} catch (Throwable e) {
log.error("system mqtrace hook init failed ,maybe can't send msg trace data", e);
}
}
boolean postSubscriptionWhenPull = Boolean.parseBoolean(properties.getProperty(PropertyKeyConst.PostSubscriptionWhenPull, "false"));
this.defaultMQPushConsumer.setPostSubscriptionWhenPull(postSubscriptionWhenPull);
String messageModel = properties.getProperty(PropertyKeyConst.MessageModel, PropertyValueConst.CLUSTERING);
this.defaultMQPushConsumer.setMessageModel(MessageModel.valueOf(messageModel));