BEA WebLogic Server 9.0新增了大量Java Message Service(JMS)功能和增强。可分为两大类:针对管理员的更改,比如JMS资源、新增的存储和转发功能以及全新的持久性存储子系统;针对开发人员的更改,比如JMS 1.1支持、Unit-of-Order增强以及消息驱动bean方面的改进。
本文从专业的角度介绍了对任何要移植到WebLogic Server 9.0的开发团队都会产生影响的关键性更改。
针对管理员的JMS更改
针对管理员的更改主要有4个。第一个与JMS资源的配置和部署方式有关。第二个是目的地管理,包括人们期待已久的查看队列或主题内容的功能。第三个是新增的存储-转发功能。最后是整个JMS子系统的基础——WebLogic Persistent Store。
JMS资源的模块化配置
在WebLogic Server 9.0出现之前,像队列和主题这样的JMS资源只能连接到特定的JMS服务器上。即便在控制台中也是这样:控制台中的队列和主题都被视为单个JMS服务器的分支。JMS资源是由WebLogic管理员在应用程序部署之前创建的。这在WebLogic Server 9.0中有了根本改变。
JMS资源现在是作为可部署资源创建的。根据weblogic-jmsmd.xsd模式定义,它们位于分离的XML文件中。这些资源可与应用程序一起配置,也可单独配置。
JMS资源可被创建为系统模块(也称为环境相关)或应用程序模块。应用程序模块的管理方式与标准J2EE模块类似,并且可以像其他J2EE应用程序一样部署为独立模块,或者作为J2EE应用程序的一部分。系统模块与应用程序模块的主要区别就是其所有者。系统资源模块由WebLogic管理员拥有并进行修改,可供所有应用程序使用。应用程序资源模块由WebLogic开发人员拥有并进行修改,开发人员将JMS资源模块打包到应用程序的EAR文件中。
可使用WebLogic控制台或WebLogic Scripting Tool(WLST)管理系统模块。每个资源由两部分构成:
第一个文件是config/config.xml配置文件,其中给出了资源的定义。
第二个XML文件位于域主目录下的config/jms目录中,其中包含JMS资源的详细信息。
通过示例可以更好地理解这些内容。我创建了一个名为MikesTestModule的系统模块。其中包含两个实体:名为MIKES_TEST_QUEUE的队列及名为MIKES_TEST_TOPIC的主题。下面的代码片断描述了域的config/config.xml文件中的系统模块:
<jms-system-resource>
<name>MikesTestModule</name>
<target>AdminServer</target>
<sub-deployment>
<name>MIKES_TEST_QUEUE</name>
<target>MyJMSServer</target>
</sub-deployment>
<sub-deployment>
<name>MIKES_TEST_TOPIC</name>
<target>MyJMSServer</target>
</sub-deployment>
<descriptor-file-name>jms/MikesTestModule-jms.xml
</descriptor-file-name>
</jms-system-resource>
请注意元素<descriptor-file-name/>。它引用了包含各个JMS实体的详细信息的文件。引用的config/jms/MikesTestModule-jms.xml文件如下所示:
<weblogic-jms xmlns="http://www.bea.com/ns/weblogic/90">
<queue name="MIKES_TEST_QUEUE">
<message-logging-params>
<message-logging-enabled>true</message-logging-enabled>
<message-logging-format>%headers%,%properties%
</message-logging-format>
</message-logging-params>
<jndi-name>mike.test.queue</jndi-name>
</queue>
<topic name="MIKES_TEST_TOPIC">
<jndi-name>mike.test.topic</jndi-name>
</topic>
</weblogic-jms>
通过创建一个遵循weblogic-jmsmd.xsd模式(与上例中config/jms/MikesTestModule-jms.xml文件的模式相同)的XML文件,即可配置应用程序模块。根据说明文档中的论述,应用程序模块必须包含在应用程序EAR文件中,并在weblogic-application.xml文件中进行引用。部署了包含JMS应用程序模块的EAR文件之后,为资源定义持久性存储就是管理员的任务了。
对系统模块和应用程序模块的选择取决于IT团队的经验。在需要与其他消息传递产品交互的环境中,采用系统模块部署通常最为适合,而仅在内部使用WebLogic JMS队列或主题的应用程序则更适合采用应用程序模块。
系统模块和应用程序模块都是由以下实体中的一项或多项组成的:
JMS队列和JMS分布式队列
JMS主题和分布式主题
配额
模板
连接工厂
外部服务器
目的地关键字
存储-转发导入的目的地
远程存储-转发上下文
存储-转发错误处理
然后,模块中的各实体将一个现有的JMS服务器作为目标。有些实体(如:连接工厂)也可以以WebLogic服务器或集群为目标。
图1展示了显示MikesTestModule示例模块的管理员控制台,该模块有两个实体,均以名为MyJMSServer的JMS服务器为目标。
图1. 显示模块实体
将可部署的JMS资源与WebLogic 8中的配置进行比较,其优势清楚可见:
管理员或部署人员将应用程序及其全部资源从一个环境移植到另一个环境时更为轻松。需要的手动配置更少,当资源是应用程序模块时更是如此。
资源与资源配置的分离使应用程序需求分得更清楚(如:一个队列,或者队列的配置方式)。
如果应用程序在内部(此时消息不以其他应用程序为目标)使用了一些队列,应用程序模块就显得尤为便利了;这些模块可为管理员和部署人员节省大量时间。例如,根据构建过程中所生成的wlw-manifest.xml文件的定义,基于BEA WebLogic Workshop的Web应用程序需要至少两个JMS队列才能正常工作。使用可部署资源时,这些队列将随应用程序一起部署,因此部署人员不会再忘记创建它们了。
在部署开始之前——而不是部署过程中,即可检查各个文件的模式。任何曾经修改config.xml文件却因括号放置位置不当而使服务器在启动时就悲惨地发生故障的人都会对此深有体会。
总体来说,定义JMS资源的新方法最终将使管理员和部署人员的工作更为轻松。
管理JMS目的地
BEA WebLogic Server 9.0引入了一个控制台应用程序,它允许JMS管理员查看目的地内容,并创建新消息或删除执行中的消息。这项特性本身就足以使您升级到WebLogic Server 9.0!图2展示了示例队列中执行中的消息。
图2. 在JMS目的地中查看消息
如图2所示,队列的内容现在是可管理的。您可以创建新消息(本例中已实现了这一功能)、导入或导出消息、删除单个消息或者删除整个队列。这项功能需要在产品环境中谨慎地构建安全性后才能使用,但它简化了应用程序的开发与测试。
最后,您还可以查看各个消息的头部和内容。图3所示为图2中第二条消息的显示结果。
图3. 查看消息详细信息
这里有两个细节应该注意。首先,JMS目的地可以暂停。任何曾经遇到过消息循环问题(消息驱动bean(MDB)获取消息、抛出异常、回滚消息、下一个MDB获取消息……如此反复)的用户都会喜欢上这一功能。管理员现在可以暂停目的地,查看出问题的消息,然后采取恰当的措施。您可以将JMS目的地暂停为以下的一种或几种状态:
为生产而暂停:任何生产者尝试发送已提交的消息时都会导致异常。
为插入而暂停:禁止使用任何执行中的消息(如事务中的消息)和完全提交的消息。任何包含在执行中事务中的消息都不会出现在队列中,虽然允许事务成功完成。在队列恢复之前,消息不可用。
为消费而暂停:任何消费者都不会接收到消息。如果指定了超时设置,那么在消费恢复之前,所有同步接收者都会超时或阻塞。所有MDB也会暂停。允许所有执行中的事务都正常完成。
这几种暂停状态均可在启动时及运行时被激活。
最后值得注意的就是改进的记录功能。WebLogic Server 9.0中包含全新的WebLogic Diagnostic Service,JMS资源也可参与其中。可启动或关闭对各个JMS实体的记录,这使管理员拥有了细粒度控制权。默认情况下,日志保存在servers/<server_name>/logs/jmsServers/<jms_server_name>/jms.messages.log中,其中<server_name>表示WebLogic Server名称,而<jms_server_name>表示JMS服务器的名称。日志头部可设置为包含某些或全部标准JMS头部,还可包含任何定制的属性。下面是一个日志片断,它显示了一个消息的生产和移除。
####
<May 11, 2005 10:07:10 PM EDT>
<>
<>
<1115863630224>
<141490>
<ID:<225269.1115863629999.0>
> <test-message-6>
<MikesTestModule!MIKES_TEST_QUEUE>
<Produced>
<weblogic>
<>
<
<?xml version="1.0" encoding="UTF-8"?>
<mes:WLJMSMessagexmlns:mes="http://www.bea.com/WLS/JMS/Message">
<mes:Header/>
</mes:WLJMSMessage>>
####
<May 11, 2005 10:08:07 PM EDT>
<>
<>
<1115863687830>
<202875> <ID:<225269.1115863629999.0>>
<test-message-6> <MikesTestModule!MIKES_TEST_QUEUE>
<Removed> <weblogic> <>
<<?xml version="1.0" encoding="UTF-8"?>
<mes:WLJMSMessage xmlns:mes="http://www.bea.com/WLS/JMS/Message">
<mes:Header/>
</mes:WLJMSMessage>>
存储-转发
WebLogic Server 9.0现在能将消息转发到远程WebLogic JMS服务器上,即便此时该服务器不可用。存储-转发(store-and-forward,SAF)服务看上去就像是经过大力改进的WebLogic Message Bridge。SAF与Message Bridge的区别表现在以下三个方面:
与Message Bridge相比,SAF更快、更具可伸缩性,但非WebLogic版本或WebLogic Server 9.0之前版本的目的地依然支持Message Bridge。
SAF支持下面介绍的Unit-of-Order特性。
WebLogic Server 9.0使用SAF服务为Web Services Reliable Messaging(WSRM)提供可靠性。
SAF机制由三个部分组成:
源JMS目的地,JMS生产者将消息发送到这里。
SAF发送和接收代理,处理服务器和集群之间的消息传输。SAF接收代理仅用于WSRM。
JMS模块,其中包含SAM导入的目的地、SAF远程上下文以及SAF错误处理。远程上下文包含远程服务器的URL及安全凭证。导入的目的地是远程目的地的本地表示。错误处理定义了发生错误时要采取的行动。
图4展示了SAF服务移动消息的方式。在本例中,JMS生产者将消息放置在一个本地JMS目的地(队列或主题)中,并继续其工作。消息会被转发或为本地SAF发送代理所获取。代理随后将消息转发给远程SAF接收代理,如果它不可用,则消息将存储在本地服务器上直到远程系统恢复正常。如果本地服务器在SAF代理能够转发消息之前发生故障,则消息将一直持续到JMS服务器恢复正常。一旦消息抵达远程导入的目的地,JMS消费者就可获取消息。在整个WebLogic JNDI树中,JMS目的地和导入的目的地都是可用的。
图4. 存储-转发消息流
所有持久性消息都以Exactly-once的服务质量(QOS)交付,并确保有序。在一个Unit-of-Order中发送的非持久性消息以At-most-once的服务质量交付,如果发生故障,到达时可能会次序混乱。SAF队列和主题可以以三种QOS水平之一进行定义:Exactly-once(仅发送一次)、At-least-once(至少发送一次)或At-most-once(最多发送一次)。
SAF架构的关键之处在于JMS生产者和消费者均没有任何指示SAF服务已包含的标志。
WebLogic持久性存储
WebLcogic 9.0带来了一个全新的统一持久性存储子系统,在整个WebLogic服务器中,只要需要持久性,就会用到这一子系统。SAF代理、JMS服务器、可靠的Web服务、诊断服务和JTA日志都使用持久性存储。
每个WebLogic Server实例都带有默认的文件存储库,位于data\store\default目录下。任何需要持久性但未显式配置持久性存储库的子系统都将使用默认存储库。多个子系统可使用同一存储库,只要它们均以同一服务器为目标即可。存储库既可基于文件,也可基于JDBC,惟一的例外就是默认存储库,它必须是文件存储库。
拥有多个存储库以及允许多个应用程序访问同一存储库的能力使管理员设计其WebLogic域时具有很大的灵活性。例如,一个存储库可能保存在高可用的基于SAN的磁盘上,而另外一个存储库则可能基于JDBC。前者性能较高,但必须手动进行故障转移(假设为集群环境)。后者性能较低,但可支持自动化的故障转移。管理员可以根据客户需求,确定对于每个应用程序哪种存储库最适合。
提升持久性存储库性能的一个诀窍就是利用存储库的事务支持。例如,假设同一事务内包含一个JMS服务器和一个EJB计时器。若JMS服务器和EJB计时器使用同一存储库,事务可为一阶段的,只需写入存储库一次。但如果它们各自使用了存储库,事务就是两阶段的,需要对每个存储库执行两次写操作,此外还要对事务日志执行一次写操作,总共5次写操作。这听起来很让人吃惊,对于每秒要处理大量事务的系统,这样的差异对性能的影响是非常显著的。
针对开发人员的JMS更改
BEA WebLogic Server 9.0为开发人员设计了一些非常有趣的新特性,包括对JMS 1.1的支持、Unit-of-Order功能、MDB增强和基于XML的消息传递。在使用WebLogic Server 9.0时应牢记,您无需为了使应用程序在WebLogic Server 9.0中运行而更改JMS代码,除非您要使用新特性。
JMS 1.1支持
WebLogic 9完全支持JMS 1.1。根据Sun Microsystems的说明文档,JMS 1.1促成了“PTP和Pub/Sub域编程接口的统一”。其结果就是您可以创建一个处理会话,然后在同一个事务中,从队列中接收消息并将其发送到某个主题。这在JMS 1.0中是无法实现的。JMS 1.1的重要之处就在于它对JMS 1.0的向下兼容性。Unit-of-Order功能
具有遗留系统的组织经常发现有些消息传递是依赖于顺序的。过去(在J2EE出现之前)只有一个消息消费者时,顺序不是问题,但出现了MDB和集群之后,这就成为人们面临的一项巨大挑战。WebLogic Server 9.0提供了Unit-of-Order功能,部分地解决了这一问题。这项功能尤其适用于来自同一生产者的一组信息必须顺序处理的情况。
例如,生产者A在一个Unit-of-Order中发送消息X、Y和Z。MDB获取消息X并对其进行处理。消息Y和Z一直在队列中,直到MDB实例提交事务为止。只有在MDB提交消息X之后,才可以处理消息Y,依此类推。
Unit-of-Order有以下几个局限性:
Unit-of-Order不能对整个队列操作,只能针对一组消息操作。
Unit-of-Order是JMS的扩展,这意味着Unit-of-Order不能用于其他消息传递环境。
有趣的是,Unit-of-Order功能可处理分布式队列。同一个Unit-of-Order中的所有消息都将发送到同一个分布式目的地成员处。
创建Unit-of-Order的方法有两种,可通过编程创建,也可通过WebLogic控制台创建。WebLogic提供了weblogic.jms.extensions.WLMessageProducer类,该类实现了avax.jms.MessageProducer接口。BEA添加了两个方法:getUnitOfOrder()和setUnitOfOrder()。您可以使用这两个方法来设置或获取当前Unit-of-Order的名称。WebLogic管理员可为会话(通过连接工厂)和目的地配置Unit-of-Order。通过setUnitOfOrder()方法可进行重写。
有关Unit-of-Order中的消息何时交付的规则是非常复杂的。黄金法则就是如果消息生产者关闭,则当前消息处理完成;如果一个事务提交了,则所有消息均已发送。每种消息确认模式都各不相同,说明文档中对其进行了详细介绍。
MDB增强
WebLogic Server 9.0中的消息驱动bean(MDB)工具进行了重要的改进。一些增强尤为突出,排在前三位的增强处理的是消息循环问题——MDB容器试图交付消息,交付失败,消息回滚,容器重试……无限循环。
第一个改进就是管理员可暂停MDB,而无需取消应用程序的部署,见本文前面“管理JMS目的地”一节。
与第一个增强相关,在MDB抛出异常后,将消息处理自动暂停一段(可配置的)时间。
当消息发生循环时,MDB容器禁止记录每次异常。而是仅记录一次,再记录下异常发生的次数。
现在可为MDB的每个实例 创建独有的client-id,从而帮助持久性订阅者,而在WebLogic 8.1中是为MDB的每个类型创建client-id。
J2EE 1.4规范规定,MDB可以从服从JCA 1.5的适配器接收消息。您可以在weblogic-ejb-jar.xml部署描述符中设置resource-adapter-jndi-name参数,从而利用此特性。
在BEA网站中可找到MDB增强的完整列表。
XML消息传递
BEA在WebLogic Server 8.1中引入了一个XML消息类型扩展,并在WebLogic Server 9.0中对其进行了增强。weblogic.jms.extensions.XMLMessage实现了javax.jms.TextMessage接口,并公开了与org.w3c.dom.Document对象一起传送的setDocument()和getDocument()方法。该扩展是很有价值的,但如果您接合的是非WebLogic系统,那么情况可能有所不同。 结束语
WebLogic Server 9.0中的新特性为数众多,限于篇幅,不再一一介绍。这里介绍了一些关键的特性,包括改进的WebLogic控制台、MDB增强和全新的存储-转发服务。希望读完本文后,读者可以大致了解WebLogic Server 9.0为应用程序和J2EE环境带来的变化。