在Producer创建成功之后,就可以用该实例来发消息了。但肯定消息不是凭空来的,所以我们要发消息之前肯定要去创建一个消息对象。在Message就为RocketMq的消息对象,我们所有
Message msg = new Message(//
topic,
tags,
keys,
("Hello RocketMQ " + i).getBytes());
SendResult sendResult = producer.send(msg);
一般一条消息主要有四个属性Topic,tags,key,msgBody。
Topic
消息主题,一个Producer实例只能对于一个topic,一条消息也必须属于一个topic。
tags
消息标签,可用来做服务端消息过滤。一个topic下可以有很多tags,一般都通过topic+tags来消费自己想要的结果。
keys
消息关键词,查询消息使用。
msgBody
消息体,所需要发的内容。
消息创建成功,就可以调用send()
方法发送消息。 topic为消息必不可少的元素,下面我们来看看Topic从无到有的一个过程。
通过创建Message设置topic,调用
producer.send(Message)
DefaultMQProducerImpl.sendDefaultImpl
接受到message对象时,会对topic进行第一次校验.先从当前实例中查找是否有该topic,
this.topicPublishInfoTable.get(topic)
.如果没有则通过NameService查找topic
this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic)
MQClientInstance去NameServer查找路由信息.如果找不到就会在在该方法中创建一个topic的路由信息.
topicRouteData=this.mQClientAPIImpl.getDefaultTopicRouteInfoFromNameServer(defaultMQProducer.getCreateTopicKey(), 1000 * 3); if (topicRouteData != null) { for (QueueData data : topicRouteData.getQueueDatas()) { int queueNums=Math.min(defaultMQProducer.getDefaultTopicQueueNums(), data.getReadQueueNums()); data.setReadQueueNums(queueNums); data.setWriteQueueNums(queueNums); } }
topic路由信息主要包括broker的信息,队列的个数等信息.Math.min()里主要就是计算topic队列选择其中较小者为新建Topic队列数.所以在创建producer里和配置文件中设置的对topic设置的队列数并不能直接定义一个topic的队列数.后面再正真创建topic的时候还会在比较一次队列的数.
系统从NameServer获取topic信息的模板就是MixAll.DEFAULT_TOPIC,与之对应保存路径是\用户\store\config\topic.json文件.如果在topic文件中没有相对应的DEFAULT_TOPIC会出现路由信息出错的异常.- 构建好topic就跟随msg一起发送到broker端.SendMessageProcessor接受到请求会对msg进行第一次检查
super.msgCheck(ctx, requestHeader, response);
broker端从自己维护this.brokerController.getTopicConfigManager().selectTopicConfig(requestHeader.getTopic());
去查看传入topic是否存在,不存则调用TopicConfigManager.createTopicInSendMessageMethod
去创建. - createTopicInSendMessageMethod()方法中又进行了一次队列比较,为客户端传过来的队列数与topic自身默认队列数比较,还是取其最小.构建好TopicConfig对象放入
topicConfigTable
中. topicConfigTable
中包涵了所有topic的信息.通过调用抽象父类ConfigManager.persist()
的方法进行保存.保存的形式备份之前的文件,把最新文件先当成临时文件保存,然后删除备份之前文件,临时文件改为正式文件.