技术开发 频道

JMS支持

域的统一
JMS主要发布了两个规范版本,1.0.2和1.1。JMS1.0.2定义了两种消息域, 点对点(队列)和发布/订阅(主题)。 JMS1.0.2的API为每个消息领域提供了类似的类体系来处理这两种不同的消息域。 结果,客户端应用在使用JMS API时要了解是在使用哪种消息域。 JMS 1.1引进了统一域的概念来最小化这两种域之间功能和客户端API的差别。 举个例子,如果你使用的是一个JMS 1.1的消息供应者, 你可以使用同一个Session事务性地在一个域接收一个消息后并且从另一个域中产生一个消息。

JMS 1.1的规范发布于2002年4月,并且在2003年11月成为J2EE 1.4的一个组成部分, 结果,现在大多数使用的应用服务器只支持JMS 1.0.2的规范.

JmsTemplate
这里为JmsTemplate提供了两个实现。JmsTemplate类使用JMS 1.1的API, 而子类JmsTemplate102使用了JMS 1.0.2的API。
使用JmsTemplate的代码只需要实现规范中定义的回调接口。 在JmsTemplate中通过调用代码让MessageCreator回调接口用所提供的会话(Session)创建消息。 然而,为了顾及更复杂的JMS API应用,回调接口SessionCallback将JMS会话提供给用户, 并且暴露Session和MessageProducer。

JMS API暴露两种发送方法,一种接受交付模式、优先级和存活时间作为服务质量(QOS)参数, 而另一种使用缺省值作为QOS参数(无需参数)方式。由于在JmsTemplate中有多种发送方法, QOS参数用bean属性进行暴露设置,从而避免在一系列发送方法中重复。同样地, 使用setReceiveTimeout属性值来设置用于异步接收调用的超时值。

某些JMS供应者允许通过ConnectionFactory的配置来设置缺省的QOS值。 这样在调用MessageProducer的发送方法send(Destination destination, Message message) 时效率更高,因为调用时直接会使用QOS缺省值,而不再用JMS规范中定义的值。 所以,为了提供对QOS值域的统一管理,JmsTemplate必须通过设置布尔值属性isExplicitQosEnabled 为true,使它能够使用自己的QOS值。

ConnectionFactory
JmsTemplate请求一个对ConnectionFactory的引用。 ConnectionFactory是JMS规范的一部分,并被作为使用JMS的入口。 客户端应用通常作为一个工厂配合JMS提供者去创建连接,并封装一系列的配置参数, 其中一些是和供应商相关的,例如SSL的配置选项。

当在EJB内使用JMS时,供应商提供JMS接口的实现,以至于可以参与声明式事务的管理, 提供连接池和会话池。为了使用这个实现,J2EE容器一般要求你在EJB或servlet部署描述符中将JMS连接工厂声明为 resource-ref。为确保可以在EJB内使用JmsTemplate的这些特性, 客户应用应当确保它能引用其中的ConnectionFactory实现。

Spring提供ConnectionFactory接口的一个实现,SingleConnectionFactory, 它将在所有的createConnection调用中返回一个相同的连接, 并忽略close的调用。这在测试和独立的环境中相当有用, 因为同一个连接可以被用于多个JmsTemplate调用以跨越多个事务。 SingleConnectionFactory接受一个通常来自JNDI的标准ConnectionFactory的引用。

事务管理
Spring为单个JMS ConnectionFactory提供一个JmsTransactionManager来管理事务。 它允许JMS应用可以利用第7章中描述的Spring的事务管理特性。JmsTransactionManager 从指定的ConnectionFactory将一个Connection/Session对绑定到线程。然而,在一个J2EE环境, ConnectionFactory将缓存连接和会话,所以被绑定到线程的实例依赖于缓存的行为。 在一个独立的环境,使用Spring的SingleConnectionFactory将导致使用单独的JMS连接, 而且每个连接都有自己的会话。JmsTemplate也能和JtaTransactionManager 以及XA-capable的JMS ConnectionFactory一起使用以完成分布式事务。

当使用JMS API从连接创建一个Session时,跨越管理性和非管理性事务的复用代码可能会让人困惑。这是因为JMS API只提供一个工厂方法来创建会话,并且它要求事务和确认模式的值。在受管理的环境下,由事务结构环境负责设置这些值,这样在供应商包装的JMS连接中可以忽略这些值。当在一个非管理性的环境中使用JmsTemplate时,你可以通过使用属性SessionTransacted和SessionAcknowledgeMode来指定这些值。当在JmsTemplate中使用PlatformTransactionManager时,模板将一直被赋予一个事务性JMS会话。

Destination管理
Destination,象ConnectionFactories一样,是可以在JNDI中进行存储和提取的JMS管理对象。当配置一个Spring应用上下文,可以使用JNDI工厂类JndiObjectFactoryBean在你的对象引用上执行依赖注入到JMS Destination。然而,如果在应用中有大量的Destination,或者JMS供应商提供了特有的高级Destination管理特性,这个策略常常显得很笨重。高级Destination管理的例子如创建动态destination或支持destination的命名层次。JmsTemplate将destination名字到JMS destination对象的解析委派到一个DestinationResolver接口的实现。DynamicDestinationResolver是JmsTemplate 使用的默认实现,并且提供动态destination解析。同时JndiDestinationResolver作为JNDI包含的destination的服务定位器,并且可选择地退回来使用DynamicDestinationResolver提供的行为。

相当常见的是在一个JMS应用中所使用的destination只有在运行时才知道,因此,当一个应用被部署时,它不能被创建。这经常是因为交互系统组件之间的共享应用逻辑是在运行时按照已知的命名规范创建destination。虽然动态destination的创建不是JMS规范的一部分,但是许多供应商已经提供了这个功能。用户为所建的动态destination定义名字,这样区别于来临时destination,并且动态destination不会被注册到JNDI中。创建动态destination所使用的API在不同的供应商之间差别很大,因为destination所关联的属性是供应商特有的。然而,有时由供应商作出的一个简单的实现选择是忽略JMS规范中的警告,并使用TopicSession的方法createTopic(String topicName)或者QueueSession的方法createQueue(String queueName)来创建一个拥有默认属性的新destination。依赖于供应商的实现,DynamicDestinationResolver可能也能创建一个物理上的destination,而不是只是解析。

布尔属性PubSubDomain被用来配置JmsTemplate使用什么样的JMS域。这个属性的默认值是false,使用点到点的域,也就是队列。在1.0.2的实现中,这个属性值用来决定JmsTemplate将消息发送到一个队列还是主题。这个标志在1.1的实现中对发送操作没有影响。然而,在这两个实现中,这个属性决定了通过DestinationResolver的实现来解析动态destination的行为。

你还可以通过属性DefaultDestination配置一个带有默认destination的JmsTemplate。默认的destination被使用时,它的发送和接收操作不需要指定一个特定的destination。

0
相关文章