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

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

jms spring

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

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

相关文章

重温1 Android系统架构及版本

1、Linux内核层(Linux Kernel) 为Android设备的各种硬件提供了底层驱动&#xff0c;Display Driver/Camera Driver/Bluetooth Driver/Flash Memory Driver/Binder(IPC)Driver/USB Driver/Keypad Driver/WiFi Driver/Audio Drivers/Power Management 2、Libraries/Android Run…

REST资源何时应获得其自己的地址?

在纯粹的REST方法中&#xff0c;所有端点&#xff08;起始端点除外&#xff09;都是不透明的&#xff0c;不需要发布其各种详细信息。 即使使用这种方法&#xff0c;本文中的要点也很重要&#xff0c;因为服务器逻辑将必须确定何时需要结束点。 介绍 在REST体系结构中&#xf…

重温2 在Activity中使用Menu

1、引用string.xml中的字符串 1) 代码中 R.string.hello_world 2) XML中string/hello_world 2、AndroidManifest <activityandroid:name".MainActivity"android:label"string/app_name" ><intent-filter><action android:name"andr…

玩转大数据22:常见的关联规则挖掘算法

引言 关联规则挖掘是数据挖掘中的一种重要技术&#xff0c;主要用于发现数据集中项之间的有趣关系。关联规则挖掘在许多领域都有广泛的应用&#xff0c;如市场篮子分析、推荐系统等。常见的关联规则挖掘算法包括Apriori算法和FP-Growth算法。 一、Apriori算法 关联规则挖掘是…

Java 9:欢迎来到Module World

Java 9已于9月21日正式发布&#xff0c;Eclipse从Eclipse Oxygen.1a&#xff08;4.7.1a&#xff09;支持Java 9&#xff0c;让我们进入模块世界。 从此处下载Java 9&#xff0c;然后将其添加到Eclipse Installed JRE中&#xff0c;如下所示 就是这样&#xff0c;我们很高兴在…

重温5 UI开发

public class TextView extends View implements ViewTreeObserver.OnPreDrawListenerjava.lang.Object ↳android.view.View ↳android.widget.TextView Known Direct Subclasses Button,CheckedTextView,Chronometer,DigitalClock,EditText,TextClockButtonRepresents a…

JWT令牌的秘密轮换

当您使用JSON Web令牌 &#xff08; JWT &#xff09;或需要对有效载荷信息进行签名或加密的任何其他令牌技术时&#xff0c;设置令牌的到期日期很重要&#xff0c;因此&#xff0c;如果令牌到期&#xff0c;则可以假定这可能被视为安全漏洞&#xff0c;您拒绝使用此令牌进行任…

重温6 ListView相关|单位dp/sp

dp:密度无关像素。 sp&#xff1a;可伸缩像素。解决文字大小适配问题。 密度&#xff1a;Android中的密度即屏幕每英寸所包含的像素数&#xff0c;通常以dpi为单位&#xff0c;例如一个宽2英寸长3英寸手机屏幕&#xff0c;若分辨率为320*480&#xff0c;则屏幕密度为320dpi。…

wso2 esb_通过运行示例从WSO2 ESB开始

wso2 esb我最近加入了一个新任务&#xff0c;我们必须基于WSO2工具栈实施ESB解决方案。 尽管我熟悉ESB的大多数概念以及其他一些实现&#xff08;例如Mule ESB &#xff09;&#xff0c;但这是我第一次必须使用WSO2 ESB 。 幸运的是&#xff0c;有很多文档可以找到&#xff0c;…

持久化技术SharedPreferences存储

public interface SharedPreferences android.content.SharedPreferences Class Overview Interface for accessing and modifying preference data returned by getSharedPreferences(String, int). 1、调用SharedPreferences对象的edit()方法获得SharedPreferences.Editor对象…

我们相信加密! 教程

许多人认为加密是一个复杂的主题&#xff0c;这很难理解。 虽然可以实现它的某些方面&#xff0c;但是每个人都可以理解它在更高层次上的工作方式。 这就是我要处理的这篇文章。 用简单的术语解释它是如何工作的&#xff0c;然后使用一些代码。 是的&#xff0c;我们信任加密…

使用Http协议访问网络--HttpURLConnection

public abstract classHttpURLConnection extends URLConnectionjava.lang.Object ↳java.net.URLConnection ↳java.net.HttpURLConnection 1、获取HttpURLConnection实例Protected ConstructorsHttpURLConnection(URL url)Constructs a new HttpURLConnection instance …

Spring Cloud –基本设置

Spring Cloud解决了分布式系统的常见问题。 但是&#xff0c;对于只使用广为人知的整体应用程序工作的人来说&#xff0c;从一开始就跳入一长串为分布式服务设计的模式可能会让人不知所措。 本文将通过实用的方法为您介绍Spring Cloud的基础知识。 完成后&#xff0c;您不仅应该…

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

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

Spring Boot中带有CKEditor的AJAX

1.概述 在本文中&#xff0c;我们将介绍如何在Spring Boot中使用CKEditor 。 在本教程中&#xff0c;我们将导入一个包含大量数据的XML文档&#xff0c;对使用GET请求将一组数据加载到CKEditor实例的能力进行编程&#xff0c;并执行POST请求以保存CKEditor的数据。 我们将使用…

使用Http协议访问网络--HttpClient

public interface HttpClient org.apache.http.client.HttpClient HttpClient是Apache提供的Http网络访问接口。1、创建HttpClient实例HttpClient是一个接口&#xff0c;无法直接创建实例&#xff0c;通常创建一个DefaultHttpClient&#xff08;HttpClient 的SubClass&#xff…

编写测试用例

1、创建测试用例 为ComeOnBroadcastReceiverDo创建一个测试用例&#xff1a; 在导航栏File-->New-->Other 选择AndroidTestProject 2、点击next输入测试工程的name&#xff0c;选择测试工程路径 点击next,选择要测试的工程&#xff1a; 点击Finish完成测试工程的新建 被…

欢迎界面动画

实现一个欢迎界面的动画&#xff0c;即打开app显示的页面&#xff0c;动画结束后跳到Activity。 1、欢迎界面的背景是一个绿色矩形 <?xml version"1.0" encoding"utf-8"?> <shape xmlns:android"http://schemas.android.com/apk/res/andr…

IP地址分类及ISO-OSI、三次握手

1. A类地址A类地址的表示范围为&#xff1a;0.0.0.0~126.255.255.255(00000000~01111110)&#xff0c;最前面一位是“0”&#xff0c;用7位&#xff08;bit&#xff09;来标识网络号&#xff0c;24位标识主机号&#xff1b;默认网络掩码为&#xff1a;255.0.0.0&#xff0c;111…