【发布时间】:2011-08-18 05:07:30
【问题描述】:
我的应用程序在 Tomcat 下运行,其中多个 Spring 的 DefaultMessageListenerContainer 监听在 Oracle 11g Weblogic 服务器下运行的多个不同 JMS 队列。
DefaultMessageListenerContainer 配置是.. 好吧.. 默认为sessionTransacted = false 和sessionAcknowledgeMode = AUTO_ACKNOWLEDGE。我的应用程序收到的消息类型是javax.jms.TextMessage。消息的实际正文 (message.getText()) 是一个 XML 字符串。
当需要将多个应用程序实例(开发箱、测试箱等)指向同一个 JMS 服务器时,我遇到了一个问题,因此,一旦消息进入队列,不知道哪个服务器会使用它(我相信首先运行receive() 方法的那个)。问题是任何给定的应用程序实例只对专用于该特定应用程序实例的消息感兴趣,因此在当前配置下,大多数消息都会丢失(被其他应用程序实例消耗并在消息处理业务逻辑中被忽略)。
我无法控制 JMS 服务器实现,但我可以强制它将消息正文中的特定 XML 元素设置为特定于应用程序实例的值,因此我可以读取它并决定应该使用哪个应用程序实例。
最自然的方法是在DefaultMessageListenerContainer 上设置messageSelector 属性,以便在JMS 服务器上决定哪个消费者应该接收什么消息。我还了解了适用于 XML 消息类型的 Weblogic 特定 JMS_BEA_SELECT 消息选择器表达式。不幸的是,它似乎不适用于带有 XML 有效负载的 javax.jms.TextMessage 消息(或者至少我无法使其工作)。我没有运气尝试以下表达式:
<property name="messageSelector" value="JMS_BEA_SELECT('xpath', '//Event/CorrelationID/text()') = 'MY_SELECTOR_TEST_3'"/>
根据this article,其他选项有:
- 使用事务会话,然后回滚会话,以便消息返回队列并可供其他应用程序实例使用。
- 在创建会话时使用 Session.CLIENT_ACKNOWLEDGE,然后恢复会话,以便消息返回队列并可供其他应用程序实例使用。
我知道我需要将DefaultMessageListenerContainer 上的sessionTransacted 和sessionAcknowledgeMode 设置为非默认值(什么值?),然后在消息处理器代码中回滚会话(选项1)或不调用message.acknowledge()(选项 2)。
看起来DefaultMessageListenerContainer 控制消息处理/会话生命周期。如何自定义?
【问题讨论】:
-
我最终设置了
sessionTransacted = true(无论如何在javadoc中推荐),从SessionAwareMessageListener扩展我的消息处理器并在处理器识别消息时执行session.rollback()(我的问题中的选项1)不适用于特定的应用程序实例。它似乎工作正常,但我真的很想看到一个使用messageSelector和 xpath 将决策移动到 JMS 服务器的解决方案。
标签: java spring tomcat jms weblogic