背景描述
近日做项目用到Rocket-MQ,发现Consumer配置有pull和push两种方式,pull其实还好理解,就是push乍一听,感觉怪怪的,便想到阅读源码理解一下,话不多说正式开始
结论先行
正式开始之前,先列出几个几个问题及结论:
- 1. 默认消费方式采用的是push
- 2. push消费机制是通过注册监听器进行消息消费
- 3. push机制也会进行pull消费
正式入戏
通过查看源码包结构,定义出了看起来像是对应的类,DefaultMQPushConsumer、DefaultMQPullConsumer,后者改日再聊,先看下前者
定位结论1
看了一下结构,便开始查看构造方法,发现
这个构造方法有相对应的usage,便定位到对应的位置去,一下就定位到了
RocketMQConsumerFactory.initPushConsumer方法,唉,粗略喵一眼,看到还有一个对应的RocketMQConsumerFactory.initPullConsumer方法,这不正好对应push和pull两种模式嘛。说干就干,这两个发方法断点一下,看默认进的那个,通过debug发现进了initPushConsumer方法。
好,此时得出第一个重要结论:RocketMQ默认采用push消费模式
找找结论2
来吧,接下来又来了解下push模式是咋运行的,通过官网和百度google发现是broker主动发消息给consumer,可我没看到啊,于是就开始定位代码,于是找initPushConsumer的usage,唉,又轻轻松松发现了
下面两个判断很明显,是判断push订阅的是普通消息还是顺序消息,很明显我们就是普通消息嘛,于是看下面,看到
consumerMessage方法,进去,立马发现了下面的
我们接着看,注册的监听器在哪使用的,于是便一点点查usage,发现在
ConsumeMessageService的实现类,都用到了注册的监听器来进行消费,这里以用的最多的ConsumeMessageConcurrentlyService为例
方法名顾名思义就知道是直接消费消息调用的,接着便一步一步查usage
到这里来了,很明显,一个是client,一个是server,应该进哪个去看呢?因为我们是消费的客户端,所以我选择进入client查看
接着, 就进入到了这里,这个就很明显了,是客户端实例初始化到时候调用,后面想都能想到,肯定是
DefaultPushConsumer初始化到时候对调用该方法
到这里,第二个结论也应证了。
看能不能编出来结论3
通过观察DefaultMQPushConsumer发现了一个特别的属性
这不是push方式吗?咋还会用到pull?不应该有一个
pushInterval吗?于是又开始查usage
发现设置这个属性值,来源于这里
然后接着看,啥时候会用到
一看,像那么回事,进去看看,
DefaultMQPushConsumerImpl越来越像那么回事啊,默认MQ推送消费实现类,但一看所在的位置
这里稍稍解析下为啥这个
pullInterval会在onSuccess中使用,我的理解是,成功之后会根据条件判断是理解之行拉取消息操作还是延迟多久之后进行拉取操作,另外,这个所在的pullMessage方法也是在需要重试的时候才会调用
有点让人难以接受,为啥会是pullMessage方法啊?不应该是pushMessage方法吗?说好的push呢?然后又继续捞usage
追到了
PullMessageService的run方法,发现这里面在从messageRequestQueue里面取消息来进行拉取,然后又去找哪里往队列里塞的呢?
经过一步步的usage查找,最终找到了在客户端启动时执行的任务,找到了对应的引用,即消费失败重试的时候会用到
到这里,三个结论终于找到了出处。
过程没有完整贴上来,因为涉及的源码太多了,不过我每个截图,都把对应的class贴上来了,大家可以大致跟着响应的class和method定位到具体的流程,可能有些不完善的,欢迎大家提建议。