JMS和Spring:有时很重要的小事情

JmsTemplate和DefaultMessageListenerContainer是用于访问JMS兼容MOM的Spring帮助器。 他们的主要目标是在JMS API之上形成一层,并处理诸如事务管理/消息确认之类的基础结构,并隐藏JMS API的某些重复和笨拙的部分(保留在那里: JMS 2.0即将来临!)。 要使用这些帮助程序中的任何一个,都必须为其提供(至少) JMS ConnectionFactory和有效的JMS Destination 。

在应用程序服务器上运行应用程序时,很有可能使用JEE架构定义ConnectionFactory。 这简化了添加ConnectionFactory及其配置参数的过程,从而允许它们以给定的别名(例如jms / myConnectionFactory)在目录服务中发布。 在你内
应用程序,例如,如果需要更多配置来查找ConnectionFactory并将其传递给JmsTemplate和/或DefaultMessageListenerContainer,则可以使用JEE命名空间或JndiTemplate / JndiObjectFactoryBean bean中的“ jndi-lookup”。

后者是JMS目的地,标识要向其生成消息或从中使用消息的JMS队列或主题。 但是,这两个JmsTemplate作为DefaultMessageListenerContainer都有两个不同的属性用于注入目标。 有一种方法将目的地作为String ,将目的地作为JMS Destination类型。 Spring并没有发明这种功能, JMS规范提到了两种方法:

4.4.4 Creating Destination Objects
Most clients will use Destinations that are JMS administered objects that they have looked up via JNDI. This is the most portable approach.
Some specialized clients may need to create Destinations by dynamically manufacturing one using a provider-specific destination name. 
Sessions provide a JMS provider-specific method for doing this.

如果将目标作为String传递,则助手将隐藏将它们映射到有效JMS目标所需的额外步骤。 最后,JMS会话上的createConsumer希望您在返回MessageConsumer之前传递Destination对象,以指示从何处使用消息。 当将目的地配置为String时,Spring会使用JMS API本身来查找目的地。 默认情况下,JmsTemplate和DefaultMessageListenerContainer具有对DestinationResolver的引用,默认情况下为DynamicDestinationResolver (稍后会对此进行详细介绍)。 下面的代码是DynamicDestinationResolver的摘录,突出显示的行指示使用JMS API将String转换为Destination(在此示例中为Queue):

protected Queue resolveQueue(Session session, String queueName) throws JMSException {if (session instanceof QueueSession) {// Cast to QueueSession: will work on both JMS 1.1 and 1.0.2return ((QueueSession) session).createQueue(queueName);}else {// Fall back to generic JMS Session: will only work on JMS 1.1return session.createQueue(queueName);}}

规范提到的另一种方法(JNDI方法)是将Destinations配置为应用程序服务器上的可管理对象。 这遵循ConnectionFactory的原理。 该目的地发布在应用程序服务器目录中,并且可以通过其JNDI名称(例如jms / myQueue)进行查找。 再次,您可以在应用程序中查找JMS目标,并使用以JMS目标为参数的属性将其传递给JmsTemplate和/或DefaultMessageListenerContainer。

现在,为什么我们有这两种选择?

我一直认为这是在方便性(动态方法)和环境透明性/可配置性(JNDI方法)之间选择的问题。 例如:在某些情况下,物理目标的名称可能会有所不同,具体取决于应用程序运行的环境。 如果在应用程序内部配置物理目标名称,则显然会失去此好处,因为如果不重建应用程序就无法更改它们。 另一方面,如果将它们配置为受管理对象,则只需更改应用程序服务器配置中的物理目标名称即可。

记得; 可以配置物理目标名称很有意义。 除了目标类型之外,处理消息传递的应用程序也不了解其详细信息。 消息传递目标没有功能协定,并且其任何属性(物理目标,持久性等)对于您编写的代码都不重要。 实际合同位于消息本身(标题和正文)内部。 另一方面,数据库表只是一个示例,它确实暴露了契约并与您的代码紧密结合。 在大多数情况下,重命名数据库表确实会影响您的代码,因此,与消息传递目标相比,使这种可配置项通常没有附加值。

最近,我发现我对这的理解还不是全部。 该规范(摘自上面某些段落的“ 4.4.4创建目标对象”)已经给出了提示:“大多数客户端将使用目标,这些目标是他们通过JNDI查找的JMS管理的对象。 这是最便携的方法。” 基本上,这告诉我们另一种方法(将目标作为String的动态方法)是“最少可移植”的方法。 对我来说,这从来都不是很清楚,因为每个提供程序都必须实现这两种方法,但是必须在更广泛的范围内考虑“便携式”。

当将Destination配置为String时,Spring在创建新的JMS Session时默认会将其转换为JMS Desintations。 当使用DefaultMessageListenerContainer消费消息时,您处理的每条消息都在事务中发生,并且默认情况下,JMS会话和使用者没有被合并,因此将为每个接收操作重新创建它们。 每次容器检查新消息和/或接收新消息时,这都会导致将String转换为JMS Destination。 “非便携式”方面发挥了作用,因为这还意味着此转换的细节和成本完全取决于MOM的驱动程序/实现。 在我们的案例中,我们在Oracle AQ作为MOM提供商方面经历了这一情况。 每当目标转换发生时,驱动程序都会执行一个特定的查询:

select   /*+ FIRST_ROWS */  t1.owner, t1.name, t1.queue_table, t1.queue_type, t1.max_retries, t1.retry_delay, t1.retention, t1.user_comment, t2. type , t2.object_type, t2.secure
from  all_queues t1, all_queue_tables t2
where  t1.owner=:1 and  t1.name=:2 and  t2.owner=:3 and  t1.queue_table=t2.queue_table

论坛条目可以在这里找到 。

尽管此查询在最新的驱动程序中得到了改进(如错误报告所提及),但它仍然导致数据库的大量开销。 解决此问题的两个选项:

  • 执行规范建议的操作:将目标配置为应用程序服务器上的资源。 每次应用程序服务器都会分发相同的实例,因此它们已经被缓存在那里。 即使您每次查找都会收到相同的实例,但是在使用JndiTemplate(或JndiDestinationResolver,请参见下文)时,它也会在应用程序一侧被阻塞,因此即使查找本身也只会发生一次。
  • 在DefaultMessageListenerContainer上启用会话/消费者缓存。 将缓存设置为使用方时,由于使用方持有对目标的引用,因此它还会间接重用目标。 这个池是Spring添加的功能, JavaDoc说它在使用资源本地事务时是安全的,而在使用XA事务时(在JBoss 4上运行除外)“应该”是安全的。

首先可能是最好的。 但是,在我们的情况下,所有目标均已在应用程序内定义(并且有很多目标),因此无需对其进行配置。 仅出于此技术原因而对它们进行重构将产生大量开销,而没有其他优势。 第二种解决方案是最不受欢迎的解决方案,因为这将意味着需要进行额外的测试和研究以确保没有任何问题。 同样,这似乎还需要做更多,因为在我们的案例中,没有迹象表明创建会话或使用者对性能有可衡量的影响。 根据JMS规范:

4.4 Session
A JMS Session is a single-threaded context* for producing and consuming
messages. Although it may allocate provider resources outside the Java virtual
machine, it is considered a lightweight JMS object.

顺便说一句; 这对于MessageConsumers / Producers也有效。 它们都绑定到一个会话,因此,如果一个会话轻量级可以打开,那么这些对象也将打开。

但是,还有第三种解决方案。 自定义的DestinationResolver。 DestinationResolver是负责从String到Destination的抽象。 缺省( DynamicDestinationResolver )在JMS会话上使用createConsumer(javax.jms.Destination)进行转换,但不会缓存生成的Destination。 但是,如果将Destinations在应用程序服务器上配置为资源,则可以(除了使用Spring的JNDI支持并直接注入Destination之外)还可以使用JndiDestinationResolver 。 该解析器会将提供的String视为JNDI位置(而不是物理目标名称),并为您执行查找。 默认情况下,它将缓存生成的目标,避免任何后续的JNDI查找。 现在,还可以将JndiDestinationResolver配置为DynamicDestinationResolver的缓存装饰器。 如果将fallback设置为true,它将首先尝试使用String作为从JNDI查找的位置,如果失败,它将使用JMS API将我们的String传递给DynamicDestinationResolver,以将我们的String转换为Destination。 在这两种情况下,都将生成的目标存储在缓存中,因此将从缓存中为对同一目标的下一个请求提供服务。 使用此解析器,可以直接使用一个解决方案,而无需编写任何代码:

<bean id="cachingDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver"><property name="cache" value="true"/><property name="fallbackToDynamicDestination" value="true"/> </bean><bean id="infra.abstractMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" abstract="true"><property name="destinationResolver" ref="cachingDestinationResolver"/>...</bean>

通过内部使用ConcurrentHasmap存储绑定,JndiDestinationResolver是线程安全的。 根据JMS 1.1规范(2.8多线程),JMS目标本身就具有线程安全性,并且可以安全地进行缓存:

jmsObjects

这再次是一个很好的例子,说明简单的事情有时会产生重要的影响。 这次,借助Spring,解决方案非常简单。 但是,最好将缓存行为设置为默认值,因为这会使它与查找目的地的任何提供程序特定的怪癖脱钩。 这不是默认值的原因可能是因为DefaultMessageListenerContainer支持动态更改目的地 (例如,使用JMX):

Note: The destination may be replaced at runtime, with the listener container picking up the new destination immediately (works e.g. with DefaultMessageListenerContainer, as long as the cache level is less than CACHE_CONSUMER). However, this is considered advanced usage; use it with care!

参考: JMS和Spring:小事情有时很重要 ,这是我们的JCG合作伙伴 Koen Serneels在技术博客上写的。

翻译自: https://www.javacodegeeks.com/2013/04/jms-and-spring-small-things-sometimes-matter.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368467.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python 音速_webpack多页应用架构系列(十一):预打包Dll,实现webpack音速编译

前言上文说到我们利用webpack来打包一个可配置的bootstrap&#xff0c;但文末留下一个问题&#xff1a;由于bootstrap十分庞大&#xff0c;因此每次编译都要耗费大部分的时间在打包bootstrap这一块&#xff0c;而换来的仅仅是配置的便利&#xff0c;十分不划算。我也并非是故意…

whereis 命令

可以用来查看命令的路径&#xff0c;安装在哪里 whereis命令是定位可执行文件、源代码文件、帮助文件在文件系统中的位置 [rootsalt-server-192 a]# whereis mysql mysql: /usr/bin/mysql /usr/lib64/mysql /usr/share/mysql /usr/share/man/man1/mysql.1.gz 转载于:https://ww…

css实现3D立方体旋转特效

先来看运行后出来的效果 它是在不停运行的一个立方体 先来看html部分的代码 <div class"rect-wrap"> <!--舞台元素&#xff0c;设置perspective&#xff0c;让其子元素获得透视效果。--><div class"container"> <!-- 容器&#…

Eclipse中的Tomcat:6个流行的“如何”问题

学习新技术总是一个艰难的过程。 当您尝试学习将要相互交互的两种技术时&#xff0c;此过程将变得更加困难。 Tomcat和Eclipse是Java EE开发中最流行的先决条件。 因此&#xff0c;要成为一名专业的开发人员&#xff0c;您需要知道如何使用此对执行最需要的操作以及如何进行一些…

adc分辨率和精度的区别_科普 | 传感器的灵敏度、分辨率和精度三者之间有何区别?...

传感器作为一种检测装置&#xff0c;具有微型化、数字化、智能化、多功能化、系统化、网络化的特点。在现代工业生产尤其是自动化生产过程中&#xff0c;需要各种传感器来监视和控制生产过程中的各个参数&#xff0c;使设备工作在正常状态或最佳状态&#xff0c;并使产品达到最…

Node08 - 配置模板引擎 -(route)

1、配置模板引擎 &#xff08;01&#xff09;、输出什么东西        //view engine&#xff1a;视图模板引擎(以何种方式呈现给用户) > 指定输出html           server.set(view engine, html); &#xff08;02&#xff09;、模板文件放在哪 //views: 指定好…

for循环与foreach的区别

for循环与foreach的区别 foreach 依赖 IEnumerable. 第一次 var a in GetList() 时 调用 GetEnumerator 返回第一个对象 并 赋给a, 以后每次再执行 var a in GetList() 的时候 调用 MoveNext.直到循环结束. 期间GetList()方法只执行一次. 1 2 3 4 5 6 7 8 9 10 11 12 13 fo…

SVN 定时 更新代码 Demo

1. 涉及技术&#xff1a;Winservice: 用system身份后台跑&#xff1b; Quartz&#xff1a;定时任务&#xff1b; SVN 2. 思路&#xff1a;Quartz定时调用cmd 程序,执行SVN update 命令,整个程序寄宿在Winservice3. 步骤&#xff1a;1&#xff09;service 用local system账户安…

如何在Jackson中使用PropertyNamingStrategy

Jackson api被广泛用于将json转换为Object并将Object转换为JSON。因此&#xff0c;如果您有json字符串并想在java对象中进行转换&#xff0c;请创建与json中的字段相同的bean的字段名。 Jackson在将json字段映射到java对象字段时遵循标准的bean约定&#xff0c;但是如果您有一个…

现代软件工程--阅读笔记

团队对个人的期望 &#xff08;1&#xff09;交流&#xff1a;能有效的和其他队员交流&#xff0c;从大的技术方向&#xff0c;到看似微小的问题。 &#xff08;2&#xff09;说到做到&#xff1a;“按时交付” &#xff08;3&#xff09;接受团队赋予的角色并按角色要求工作:团…

Linux上的HotSpot GC线程CPU占用空间

以下问题将测试您对Linux操作系统上运行的Java应用程序的垃圾回收和高CPU故障排除的知识。 当调查过多的GC和/或CPU利用率时&#xff0c;此故障排除技术尤其重要。 它将假定您没有访问高级监视工具的能力&#xff0c;例如Compuware dynaTrace甚至JVisualVM。 将来会介绍使用此类…

tornado-简介和原理

tornado-设计初衷 1. 追求小而精 2. epoll IO多路复用和协程 3. 支持WebSocket 4. 单线程程序(GIL限制&#xff0c;本身某种意义上不启动多进程就是单线程程序) # Python GIL介绍详情 tronado应用场景 1. 大量的http请求连接(大量的用户请求&#xff0c;要求并发性和高性能) tr…

mysql5.6.13_MySQL-5.6.13解压版(zip版)安装配置教程

1、将mysql-5.6.13-winx64.zip 解压到D:\mysql-5.6.13\目录。2、清理里面的调试文件打开这个目录&#xff0c;发现里面的文件夹和文件跟一个安装好后的MySQL基本没有区别。可能你会很郁闷&#xff0c;这个MySQL5.6.13居然有1.04GB&#xff0c;呵呵&#xff0c;仔细一看你就会发…

前端学习笔记--HTTP缓存

原文地址&#xff1a;https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hlzh-cn 缓存并重用之前获取的资源的能力是性能优化的一个关键方面。 每个浏览器都自带了 HTTP 缓存实现功能&#xff0c;只需要确保每个服务…

socket programming

进行 socket programming开始要做的工作&#xff1a; On Linux: 以下是client代码&#xff0c;使用TCP&#xff0c;注意网络字节序&#xff1a; 1 #include <sys/socket.h> 2 #include <netinet/in.h> 3 #include <arpa/inet.h> 4 int main() 5 { 6 …

如何用Veripacks替换构建模块

比较下面的两棵树。 在这两种情况下&#xff0c;目标都是拥有一个具有两个独立模块&#xff08; frontend和reporting &#xff09;和一个共享/公用模块&#xff08; domain &#xff09;的应用程序。 frontend的代码不应访问reporting代码&#xff0c;反之亦然。 两个模块都可…

JS的DOM和BOM

* JavaScript分三个部分: ECMAScript标准:JS的基本的语法DOM:Document Object Model --->文档对象模型----操作页面的元素BOM:Browser Object Model----->浏览器对象模型---操作的是浏览器一、DOM对象 文档:把一个html文件看成是一个文档,由于万物皆对象,所以把这个文档看…

mysql建表的规则_MYSQL建表规则 - Love彼岸花开的个人空间 - OSCHINA - 中文开源技术交流社区...

建立表规约【强制】表名、字段名必须使用小写字母或数字&#xff0c;禁止出现数字开头&#xff0c;禁止两个下划线中间只 出现数字。数据库字段名的修改代价很大&#xff0c;因为无法进行预发布&#xff0c;所以字段名称需要慎重考虑。说明&#xff1a;MySQL 在 Windows 下不区…

数据库(11)-- Hash索引和BTree索引 的区别

索引是帮助mysql获取数据的数据结构。最常见的索引是Btree索引和Hash索引。 不同的引擎对于索引有不同的支持&#xff1a;Innodb和MyISAM默认的索引是Btree索引&#xff1b;而Mermory默认的索引是Hash索引。 Hash索引 哈希索引包含以数组形式组织的 Bucket 集合。 哈希函数将索…

JBoss AS 8中的Java EE 7和EJB 3.2支持

你们中有些人可能已经知道Java EE 7规范的Public Final Draft版本已经发布 。 除此以外&#xff0c;此版本的Java EE还引入了EJB规范的EJB 3.2版本。 与EJB 3.1规范相比&#xff0c;EJB 3.2具有一些新功能。 我在这里引用EJB 3.2规范中的文本&#xff0c;总结了新功能&#xff…