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目标本身就具有线程安全性,并且可以安全地进行缓存:

这再次是一个很好的例子,说明简单的事情有时会产生重要的影响。 这次,借助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

jms spring

jms spring_JMS和Spring:有时很重要的小事情相关推荐

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

    JmsTemplate和DefaultMessageListenerContainer是用于访问JMS兼容MOM的Spring帮助器. 他们的主要目标是在JMS API之上形成一层,并处理诸如事务管理 ...

  2. springboot导入项目依赖报错_使用Spring Boot很简单,go!!!

    Spring Boot依赖 使用Spring Boot很简单,先添加基础依赖包,有以下两种方式 1. 继承spring-boot-starter-parent项目    org.springframe ...

  3. 一个用Spring Boot做的垃圾分类小程序,你不拿来学习一下?

    今天TJ君看到一个很有意思的小项目,赶紧来和大家分享一下~ 各位程序猿们各自生活的城市对于垃圾分类估计都推行了一段时间,小伙伴们应该都已经养成了扔垃圾之前进行分类的习惯,但是偶尔也会有想不起来一样东西 ...

  4. Spring Boot 配置随机数那些小技巧

    转载自  Spring Boot 配置随机数那些小技巧 Spring Boot支持在系统加载的时候配置随机数. 添加config/random.properties文件,添加以下内容: #随机32位M ...

  5. spring mvc文件上传小例子

    spring mvc文件上传小例子 1.jsp页面 <%@page contentType="text/html;charset=UTF-8"%> <%@page ...

  6. 心得体悟帖---16、哪些看起来很难做的事情真的不过如此

    心得体悟帖---16.哪些看起来很难做的事情真的不过如此 一.总结 一句话总结: 你可能会因为激情缺乏非常抵触做什么事情,但是当你做了之后,你会发现其实感觉都还挺好的. 做着做着,你会发现感觉其实挺舒 ...

  7. java notify视频_一个很好的小例子来演示java中的wait()和notify()方法

    任何人都可以在 java中为我提供一个很好的小例子演示wait()和notify()功能.我尝试使用下面的代码,但它没有显示我的预期. public class WaitDemo { int i = ...

  8. Delphi字符串转日期,强大到窒息,VarToDateTime解决了困扰很久的小问题

    Delphi字符串转日期,强大到窒息,VarToDateTime解决了困扰很久的小问题 参考文章: (1)Delphi字符串转日期,强大到窒息,VarToDateTime解决了困扰很久的小问题 (2) ...

  9. 【自动驾驶】鸽了很久的小物体目标检测代码【小物体目标检测】

    鸽了很久的小物体目标检测代码 https://github.com/LT1st/SmallObstacleDetection/tree/main/code#readme Pytorch: Small ...

最新文章

  1. [UTCTF2020]Cube Crypto
  2. python线性回归算法简介_Python机器学习(二):线性回归算法
  3. 手写vue2的Lazyload
  4. 设计模式之组合模式(Composite 模式)
  5. 【Java】Junit、反射和注解的笔记
  6. 2010计算机知识点总结,2010年全国职称计算机考试:知识点笔记第一章
  7. 简单的eda实验vga在linux系统中,《EDA实验报告VGA彩条显示.doc
  8. c语言 指针混合编程,entern “C”/(C/C++)混合编程(转)
  9. 方舟服务器在线人数查询软件,方舟生存进化怎么查看在线人数
  10. 老板杜绝员工上班不务正业
  11. SpringBoot2——web开发(组件使用)
  12. 电子计算机技发展趋势,现代电子信息技的现况及发展趋势.ppt
  13. Html 实现手风琴效果
  14. Kaggle泰坦尼克号生存预测挑战——数据分析
  15. python实现一元线性回归预测电影票房收入
  16. 手机计算机藏应用,手机“计算器”隐藏功能,一键把隐私照片加密
  17. abs和pc混在一起怎么解决_PC/ABS常见问题及解决方案
  18. 2020-11-22
  19. php 可视化编辑建站源码,CmsEasy可视化编辑商城系统 v7.3.1
  20. Raspberry Pi 树莓派连接温度传感器DS18B20

热门文章

  1. 16、java中的集合(3)
  2. IDEA的debug方法头坑
  3. JavaScript学习总结(七)——JavaScript函数(function)
  4. 高级 | Java中获取类名的3种方法
  5. JDK8新特性之方法引用
  6. MySQL查询出来的不重复
  7. JS中DOM节点的CRUD
  8. 2019蓝桥杯省赛---java---C---4(质数)
  9. 2020蓝桥杯省赛---java---B---4( 合并检测)
  10. php移动代码,移动专区周级收录如何提交 复制这段php代码即可