深入理解DefaultMessageListenerContainer
DefaultMessageListenerContainer是一个用于异步消息监听的管理类。
DefaultMessageListenerContainer最简单的实现逻辑,一个任务执行器,执行任务(即消息监听)。
DefaultMessageListenerContainer实现的主要原理是,通过内部初始化建立的一个taskExecutor(默认是SimpleAsyncTaskExecutor)用于执行消息监听的任务(AsyncMessageListenerInvoker)。
这里默认的任务执行器是SimpleAsyncTaskExecutor,这个执行器的缺点是不会重用连接,也就是对于每个任务都需要新开启一个线程,执行完任务后会关闭它。如果要优化的话可以考虑线程池。
消息监听的任务被抽象成AsyncMessageListenerInvoker类,这个类实现了Runnable接口,内部run方法其实是通过不断循环consumer.recieve()方法来实现监听。
事实上一个消费者对应了一个AsyncMessageListenerInvoker任务,每个任务需要一个单独的线程去执行它。这个AsyncMessageListenerInvoker实例被放在了一个名为scheduledInvokers的set里面。
其实我们还有一个比较关心的地方是这个DefaultMessageListenerContainer缓不缓存connection,session,consumer。它是根据catchLevel属性来决定是否缓存connection,session,consumer。默认的catchLevel对应常量CATCH_AUTO,即由配置的外部事务管理器决定。catchLevel级别分别是CATCH_NONE,CATCH_CONNECTION,CATCH_SESSION,CATCH_CONSUMER,分别对应0,1,2,3。我试了下默认的CATCH_AUTO在没有定义事务管理时值为 CATCH_CONSUMER,即3。
DefaultMessageListenerContainer会根据catchLevel来缓存共享connection,session,及consumer。值为3的话就会缓存connection,session,及consumer,在初始化的时候就会调用父类AbstractJmsListeningContainer的doStart()方法,判断cacheLevel是否大于等于1,如果大于就创建一个connection将放入成员变量sharedConnection中。
每个任务被执行的时候(即责任是监听消息),会先去获取connection,session及consumer(通过调用initResourcesIfNecessary方法)就像我们自己最初实现一个简单的客户端消费者一样。只不过这里会根据catchLevel来决定是否缓存session及consumer。被缓存了的session及consumer放在对应的成员变量里面。
接着任务会想要执行consumer.recieve方法,这之前肯定要获取onnection,session及consumer,如果已有onnection,session及consumer则获取过来,如果没有则通过配置的信息新建。执行完consumer.recieve后,会判断consumer.recieve返回的消息是否为空。
不为空则调用message对应的messageListner(之前我们在DefaultMessageListenerContainer中通过方法setMessageListner设置的)的onMessage执行相应的逻辑,并设置这个任务的Idle为false,表明这个任务不是空闲的,然后会调用方法判断是否应该新建任务实例,这个受限于MaxConcurrentConsumers及IdleTaskExecutionLimit。为空则不需要特别处理,只需调用noMessageReceived方法将idle标记设为true。
任务执行完后,会在finally处释放connection,session及consumer。这个是根据上述讲的catchLevel来设置的。
继承体系如下:

AbstractJmsListeningContainer提供了一个最上层最基础的jms消息监听管理类所应该有的方法。提供了start(启动这个管理类),stop,initialize(初始化这个管理类),establishSharedConnection等。
====================
http://blog.sina.com.cn/s/blog_6592ed330100loqk.html
DefaultMessageListenerContainer继承自AbstractPollingMessageListenerContainer,主要使用同步的方式接收消息(也就是通过循环调用MessageConsumer.receive的方式接收消息)。该类主要的属性如下:
- private int concurrentConsumers = 1;
- private int maxConcurrentConsumers = 1;
- private int maxMessagesPerTask = Integer.MIN_VALUE;
- private int idleTaskExecutionLimit = 1;
- private final Set scheduledInvokers = new HashSet();
- private TaskExecutor taskExecutor;
- private int cacheLevel = CACHE_AUTO
跟SimpleMessageListenerContainer一样,DefaultMessageListenerContainer也支持创建多个Session和MessageConsumer来接收消息。跟SimpleMessageListenerContainer不同的是,DefaultMessageListenerContainer创建了concurrentConsumers所指定个数的AsyncMessageListenerInvoker(实现了SchedulingAwareRunnable接口),并交给taskExecutor运行。
maxMessagesPerTask属性的默认值是Integer.MIN_VALUE,但是如果设置的taskExecutor(默认值是SimpleAsyncTaskExecutor)实现了SchedulingTaskExecutor接口并且其prefersShortLivedTasks方法返回true(也就是说该TaskExecutor倾向于短期任务),那么maxMessagesPerTask属性会自动被设置为10。
如果maxMessagesPerTask属性的值小于0,那么AsyncMessageListenerInvoker.run方法会在循环中反复尝试接收消息,并在接收到消息后调用MessageListener(或者SessionAwareMessageListener);如果maxMessagesPerTask属性的值不小于0,那么AsyncMessageListenerInvoker.run方法里最多会尝试接收消息maxMessagesPerTask次,每次接收消息的超时时间由其父类AbstractPollingMessageListenerContainer的receiveTimeout属性指定。如果在这些尝试中都没有接收到消息,那么AsyncMessageListenerInvoker的idleTaskExecutionCount属性会被累加。在run方法执行完毕前会对idleTaskExecutionCount进行检查,如果该值超过了DefaultMessageListenerContainer.idleTaskExecutionLimit(默认值1),那么这个AsyncMessageListenerInvoker可能会被销毁。
所有AsyncMessageListenerInvoker实例都保存在scheduledInvokers中,实例的个数可以在concurrentConsumers和maxConcurrentConsumers之间浮动。跟SimpleMessageListenerContainer一样,应该只是在Destination为Queue的时候才使用多个AsyncMessageListenerInvoker实例。
cacheLevel属性用于指定是否对JMS资源进行缓存,可选的值是CACHE_NONE = 0、CACHE_CONNECTION = 1、CACHE_SESSION = 2、CACHE_CONSUMER = 3和CACHE_AUTO = 4。默认情况下,如果transactionManager属性不为null,那么cacheLevel被自动设置为CACHE_NONE(不进行缓存),否则cacheLevel被自动设置为CACHE_CONSUMER。
如果cacheLevel属性值大于等于CACHE_CONNECTION,那么sharedConnectionEnabled方法(在AbstractJmsListeningContainer中定义)返回true,也就是说使用共享的JMS连接。
深入理解DefaultMessageListenerContainer的更多相关文章
- 理解CSS视觉格式化
前面的话 CSS视觉格式化这个词可能比较陌生,但说起盒模型可能就恍然大悟了.实际上,盒模型只是CSS视觉格式化的一部分.视觉格式化分为块级和行内两种处理方式.理解视觉格式化,可以确定得到的效果是应 ...
- 彻底理解AC多模式匹配算法
(本文尤其适合遍览网上的讲解而仍百思不得姐的同学) 一.原理 AC自动机首先将模式组记录为Trie字典树的形式,以节点表示不同状态,边上标以字母表中的字符,表示状态的转移.根节点状态记为0状态,表示起 ...
- 理解加密算法(三)——创建CA机构,签发证书并开始TLS通信
接理解加密算法(一)--加密算法分类.理解加密算法(二)--TLS/SSL 1 不安全的TCP通信 普通的TCP通信数据是明文传输的,所以存在数据泄露和被篡改的风险,我们可以写一段测试代码试验一下. ...
- node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理
一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...
- 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念
一.前言 DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...
- 学习AOP之透过Spring的Ioc理解Advisor
花了几天时间来学习Spring,突然明白一个问题,就是看书不能让人理解Spring,一方面要结合使用场景,另一方面要阅读源代码,这种方式理解起来事半功倍.那看书有什么用呢?主要还是扩展视野,毕竟书是别 ...
- ThreadLocal简单理解
在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...
- JS核心系列:理解 new 的运行机制
和其他高级语言一样 javascript 中也有 new 运算符,我们知道 new 运算符是用来实例化一个类,从而在内存中分配一个实例对象. 但在 javascript 中,万物皆对象,为什么还要通过 ...
- 深入理解JS 执行细节
javascript从定义到执行,JS引擎在实现层做了很多初始化工作,因此在学习JS引擎工作机制之前,我们需要引入几个相关的概念:执行环境栈.全局对象.执行环境.变量对象.活动对象.作用域和作用域链等 ...
随机推荐
- sqlalchemy.exc.CompileError: (in table 'user', column 'username'): VARCHAR requires a length on dialect mysql
映射数据库时报错:sqlalchemy.exc.CompileError: (in table 'user', column 'username'): VARCHAR requires a lengt ...
- python自动化
自动化测试一些问题 什么是自动化测试? 自动化测试,顾名思义,自动完成测试工作.通过一些自动化测试工具或自己造轮子实现模拟之前人工点点/写写的工作并验证其结果完成整个测试过程,这样的测试过程,便是自动 ...
- html知识补充
1.点击超链接跳转到新窗口 <a href="http://www.baidu.com" target="_blank">百度一下</a> ...
- python常用内置方法
常用内建函数# 如何在遍历一个列表的同时获取当前下标? # 普通人的做法 list = [1, 2, 3, 4, 5, 6] index = 0 for i in list: print('下标%s' ...
- 1. let与const
1.ES6 新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. var a = []; for (var i = 0;i<10;i++) ...
- dell 7559 安装Manjaro 18
本来是装黑苹果的,折腾好几天都装好了,是可以正常使用的,可是clover始终有一个问题,每次启动前需要覆盖一遍EFI分区内EFI目录的CLOVER目录内的所有文件,方能引导MAC. 不然就卡Init ...
- CF277B Set of Points——构造题
题意 构造 $n$ 个点使其凸度(顶点数最多的凸多边形的顶点数)恰好为 $m$,且任意三点不能共线. (题意有点绕,建议看英文原文 分析 首先,题目并不是求凸包上的顶点数,而是求能形成的凸多边形的最大 ...
- Git - Q
GIT :实现版本控制的软件 命令: git init # 初始 git (先执行这个才能执行接下来的) git status # 查看当前文件夹状态 git add 文件名 # 对指定文件进行版本控 ...
- Educational Codeforces Round 75 (Rated for Div. 2) B. Binary Palindromes
链接: https://codeforces.com/contest/1251/problem/B 题意: A palindrome is a string t which reads the sam ...
- MongoDB 分片管理(一)检查集群状态
一.检查集群状态 1.1 使用sh.status()查看集群摘要信息 1.使用sh.status()可以查看分片信息.数据库信息.集合信息 sh.status() 如果数据块较多时,使用sh.stat ...