开始

想要搞通SimpleMessageListenerContainer的原理,就要深入到源码里面。
image.png
发现,简单的消息容器,继承了抽象的消息容器
image.png
我们再点进去这个抽象的消息容器
image.png
image.png

ApplicationContextAware这个接口我们比较熟悉了。
image.png
这个接口里面有setApplicationContext方法。
image.png
最关键的接口是MessageListenerContainer
image.png
这个接口,它又继承了SmartLifecycle
image.png

image.png
Lifecycle是Spring框架的接口。
image.png
它有一个start方法。在这个Bean被交给Spring框架的时候,这个Bean被启动的时候,Spring框架会自动的调用这个Bean的或者叫做这个对象的start方法。
image.png
我们一直往上找到Lifecycle就表示,这个简单消息容器会被调用它的start的方法在启用的时候。
image.png
我们就去找它的structure里面去找,找他有没有start方法。
image.png
没有找到start方法,说明start方法在它的父类里面实现的。
image.png

我们进入到这个抽象类里面
image.png
进入这里再找start方法
image.png

找到了start方法,还可以看到是继承自Lifecycle这个接口。
image.png
双击打开这个start方法,这个方法逻辑是什么呢?判断这个Bean有没有被初始化。
image.png
这里是最重要的 ,它调用了doStart方法
image.png
我们按住arl+alt+B看下实现
image.png
我们用的这个SimpleMessageListenerContainer简单消息监听容器也实现了doStart .所以它调用的时候会自动调用到子类的doStart方法。
image.png

image.png
我们来看下子类的doStart方法做了什么。首先它调用了父类的doStart方法。
image.png

image.png
我们点进去initializeConsumers
image.png
它新建了一个HashSet
image.png
然后在HashSet里面createBlockingQueueComsumer
image.png

看下createBlockingQueueComsumer
image.png

image.png
专业的消费者,包装了有关这个消息Broker的connection。就是它将spring boot应用和rabbitMQ之间的链接的消息和信息都包装起来了。而且它有自己的生命周期。就是说我们所有的监听类都要通过在这个BlockingQueueConsumer来实现。它包装了connection和channel
image.png
我们new出来的consumer被返回回去了。
image.png
返到了这个地方
image.png

也就是说,这个这个consumers是SimpleMessageListenerContainer的成员,里面持有了一堆BlockingQueueConsumer类。BlockingQueueConsumer这个类里面又封装了我们跟真正的rabbitMQ通信的channel和connection
image.png

这里new了一些 AsyncMessageProcessingConsumer
image.png
进入类AsyncMessageProcessingConsumer
image.png
我们发现AsyncMessageProcessingConsumer是SimpleMessageListenerContainer的内部类
image.png
内部类有两个成员, 持有BlockingQueueConsumer .这列的主要作用是持有我们新建的BlockingQueueConsumer
image.png

image.png

image.png

image.png
返回的是父类里面的成员。就是Executor 线程池这个类。
image.png
这个类的父类有线程池,可以执行内部类叫做AsyncMessageProcessingConsumer。也就是说这个线程池是由Spring boot的类,给我们实现的。不需要我们再实现线程池了。
image.png
我们回到这个内部类。实现了Runnable
image.png
Runnable接口里面有run方法。也就是这个内部类放到线程池里面 它的run方法会自动的执行。
image.png
我们的SimpleMessageListenerContainer被新建了之后会自动的执行它的start方法,start执行执行的时候会新建BlockingQueueConsumer。
BlockingQueueConsumer它持有了和RabbitMQ通信的channel用它来通信。
image.png
用它来通信呢,我们又启用了内部类。内部类实现了Runable接口,它被放进线程池里面进行循环的调用。调用这个run方法
image.png

run方法里面有个 initialize方法。
image.png
进入这个初始化方法
image.png

调用了comsumer.start方法
image.png

这里的consumer.start方法调用的就是 BlockingQueueComsumer内的start方法。
image.png
BlockingQueueComsumer有自己的声明周期。调用start就是开始了。
image.png

start方法里面最后调用了
image.png

image.png

image.png
再往下找看到了熟悉的channel.basicComsumer
image.png
也就是说我们的SimpleMessageListenerContianer它持有了BlockingQueueComsumer类,BlockingQueueComsumer这个类负责监听rabbitMQ的一切的链接操作,
image.png
BlockingQueueComsumer里面的start方法。在初始化的时候会被定义
image.png
会调用
image.png
进入这个方法再往下找。
image.png

image.png
最后调用了 channel.basicConsume
image.png
它的回调方法
image.png

image.png
image.png

image.png

这里内部类里面有个 handleDelivery是真正的底层的回调方法,这个方法在收到消息的时候会被回调。
image.png
它的核心就是这一行代码。它将收到的新消息压到queue这个成员里面。
image.png
这个类成员就是BlockingQueue一个阻塞的队列。也就是我们收到的消息会压到这个阻塞队列里面。
image.png
那么这个阻塞队列什么时候被取用呢?我们要回到SimpleMessageListenerContainer找到run方法这里。run方法会被调用,
image.png
调用的时候,首先它会initialize方法 就是初始化。初始化的时候我们把BlockingQueueComsumer做了channel.basicComsume把它的回调函数也注册上了。每一次它收到新消息就会把消息压到BlockQueue阻塞的队列里面去。
image.png

压到BlockQueue里面之后,进入死循环,然后调用了mainLoop这个主循环。
image.png

主循环这个方法就是我们的消费者起来之后,不断的被循环调用的方法。
image.png

image.png
image.png
中间的关键代码
image.png
进入方法,往下找
image.png
又调用了comsumer的nextMessage方法
image.png
这个consumer就是BlockingQueueComsumer这个类
image.png
再点进来
image.png
最核心的代码在这里。this.queue.poll就是从队列里面拿出来。也就是说它将这个queue对象(也就是BlockingQueueConsumer这个对象,)将消息的接收和取出,完全的分离开了。消息的接收是通过basicConsume接收,但是等他去用的时候,是通过SimpleMessageListenerContainer里面的内部类的 mainLoop方法,去取用这个队列里面的消息,也就是说不光在RabbitMQ中有个主队列。Spring Boot在我们的应用里面,在内存里面,它做了一个抽象的子队列。这个抽象队列基本是作为缓冲和缓存来使用的。也就是当这个RabbitMQ有消息的时候,它先把消息取到我们的内存里面,然后等待消息进一步的被消费
image.png

消息从我们本地缓存取出来之后。它是怎么调用会我们的onMessage方法的

我们返回到这里
image.png
走到这里的executeListener的方法。
image.png
点击那里继续往下找
image.png
doExecuteListener这是核心方法,再进去
image.png
再往下找
image.png
最后调用了 invokeListener
image.png

image.png
点进去发现他是一个 函数式的接口。所以它不是方法体。
image.png

image.png
this.delegate是什么
image.png

image.png

image.png
如果类型是MessageListener类型的
image.png

image.png
最后调用了listener.onMessage方法
image.png
最后调用的就是这个方法
image.png

结束