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,一经查实,立即删除!

相关文章

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;并使产品达到最…

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…

前端学习笔记--HTTP缓存

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

如何用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文件看成是一个文档,由于万物皆对象,所以把这个文档看…

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

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

MySQL的复制:MySQL系列之十三

一、MySQL复制相关概念 主从复制&#xff1a;主节点将数据同步到多个从节点级联复制&#xff1a;主节点将数据同步到一个从节点&#xff0c;其他的从节点在向从节点复制数据同步复制&#xff1a;将数据从主节点全部同步到从节点时才返回给用户的复制策略叫同步复制异步复制&…

将NetBeans代码模板弯曲到我的意愿

任何阅读过我关于NetBeans的文章的人都知道&#xff0c;我真的很喜欢NetBeans的众多功能。 但是&#xff0c;最近&#xff0c;我发现自己对NetBeans特定功能的特定问题越来越恼火。 最终&#xff0c;它使我烦恼不已&#xff0c;促使我开始研究如何根据自己的喜好禁用或更改该功…

MySQL安装过程

最近试着重装了下MySQL&#xff0c;安装过程很简单&#xff0c;希望能帮助大家 mysql安装过程 1. 下载&#xff1a; 我下载的是64位系统的zip包&#xff1a; 下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 下载zip的包。 下载后解压到对应目录 如&#xff1a;D:…

极简的MyBatis在Spring Boot下的配置

以我的一个项目为例。 0、项目结构&#xff1a; 1、POM中添加MyBatis的依赖&#xff1a; <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.1</version> …

JPA –我应该成为懒惰的极端主义者吗?

当您与开发人员讨论将对象映射到关系数据库时&#xff0c;他们经常抱怨JPA性能差&#xff0c;JPA提供程序的行为不可预测等。通常&#xff0c;在对话的某些时候&#xff0c;您会听到&#xff1a; “让我们完全放弃这项技术&#xff0c;我们在上个月的会议上看到了更好的东西。 …

mysql恢复 报错_Mysql 数据恢复报错

1.测试mysql binlog 数据恢复功能&#xff0c;我的mysql版本是5.7.172.删了数据之后&#xff0c;执行show binlog events 命令得到如下记录3.找到开始删除和结束删除的位置&#xff0c;然后执行恢复命令:mysqlbinlog --no-defaults --start-position8991 --stop-position290468…

IONIC

1.项目摘要  随着移动互联网的不断发展&#xff0c;移动端流量所占比例已经越来越高。下图来自IResearch所做的关于移动互联网的市场调研报告 由此我们可以看出&#xff0c;移动互联网在人们生活中的位置越来越重要。 受益于国家“提速降费”以及即将取消流量漫游的优惠政策&…

line-height与图片底部间隙的学习整理转述

前言&#xff1a;这是笔者学习之后自己的理解与整理。如果有错误或者疑问的地方&#xff0c;请大家指正&#xff0c;我会持续更新&#xff01; 看大牛张鑫旭的视屏可能会理解的更深一些&#xff0c;点击这里&#xff1b; line-height&#xff0c;两行文字的基线之间的距离&…

分数DRL:在OptaPlanner中更快,更轻松

对于OptaPlanner &#xff08; Drools Planner&#xff09;6.0.0.Beta1&#xff0c;我已经用更优雅的ConstraintMatch系统替换了ConstraintOccurrence。 结果是您的DRL评分文件为&#xff1a; 快多了 更容易读写 错误的发生率要低得多&#xff0c;因为它们使分数损坏变得更加…

STM32 环境搭建

从之前的51&#xff0c;到后来的AVR&#xff0c;再到现在的STM32&#xff0c;处理器的处理能力在不断的提高&#xff0c;我们也跟随着处理器一步一步的玩到了STM32 目前STM32的开发环境很多&#xff0c;常用的例如Keil&#xff0c;IAR等&#xff0c;但是这些软件都是收费的&…

mysql数据库工程师网易微专业_网易MySQL数据库工程师微专业学习笔记(五)

一、mysql数据库中的存储引擎mysql在创建数据表时可以通过engine关键字设置存储引擎的类型&#xff0c;也可以通过alter命令来修改表的存储引擎。可以通过show engines命令来查看当前mysql数据库支持的存储引擎的类型&#xff0c;一般场景的存储引擎有&#xff1a;InnoDB、MyIS…