java - 我可以在 MDB 中获取源 JMS session 吗?

标签 java jakarta-ee jms websphere distributed-transactions

这个问题主要集中在使用 Websphere MQ (WMQ) 时的 Websphere Application Server (WAS),因为这是我最熟悉的。但是,我认为我所说的一切更普遍地适用于所有 Java EE 应用程序服务器,因为我坚持使用 Java 标准接口(interface)。我更喜欢与标准相关的解释,但我仍然对特定于 WAS/WMQ 的答案感到非常兴奋。

JMS 1.1 定义了 JMS 与应用程序服务器交互的机制。大致的过程是在某个时候创建​​一个ConnectionConsumer来监控一个Queue或者Topic。当一条消息出现时,JMS 实现从 ServerSessionPool 获取一个 ServerSession 对象,将消息加载到与 ServerSession 关联的 Session 中,然后调用 ServerSession 对象上的 start()。然后 ServerSession 负责调度消息以供 MDB 在应用程序服务器线程上进行处理。 MDB 将消息作为其 onMessage() 方法的一部分获取,并可以执行它需要的任何处理。

这一切都很好,直到 MDB 决定要发送另一条消息来响应它收到的消息。为了做到这一点,MDB 必须查找或注入(inject)一个 ConnectionFactory 对象,获取一个 Connection,然后是一个 Session,然后是一个 MessageProducer,最后发送消息。这一切看起来很浪费。作为向 MDB 传递消息的一部分,已经创建了一个 Connection 和 Session 对象。如果 MDB 能够以某种方式访问​​该 session ,它就可以避免必须执行所有这些额外的工作并避免必须创建所有这些额外的连接。这种额外的工作是一种成本——为了仅向请求消息发送回复消息,MDB 必须使用两个连接和两个 session (每个 session 用于获取消息和发送响应)。当使用全局事务时,我相信这会强制应用程序服务器将事务处理为两阶段提交事务(至少一些,如果不是全部,应用程序服务器可以优化仅涉及单个资源的全局事务,将其处理为一阶段提交)。使事务成为两阶段事务显着增加了处理消息的开销,并且还引入了各种新的复杂性(不确定事务是最大的事务之一)。

JMS 1.1 规范指出:“由于许多监听器需要使用其 session 的服务,因此监听器可能需要将其 session 作为构造函数参数传递给它”,这似乎表明它是完美的MDB 可以接受使用传递初始消息的 session 来发送响应。但是,我不知道有任何机制可以以标准方式从 MDB 中检索此 Session 对象。我也不知道有任何以非标准方式检索它的机制。我什至在任何地方都找不到与此相关的问题或博客文章。

那么,问题是:为什么会这样? JMS API 非常复杂,但是,我没有看到其中的任何内容会使 MDB 难以使用向其提供原始消息的 session 来发送响应(如果它可以访问的话)。 MDB 不能使用这个 Session 对象有什么原因吗?是否有符合标准的方法来访问 session ?有没有不符合标准的方式?应用程序服务器/JMS 实现是否可以智能地将涉及单个 JMS 队列管理器上两个连接上的操作的全局事务优化为单阶段提交事务(我对标准的研究和理解似乎表明这是不可能的)?

最佳答案

Are application servers / JMS implementations smart to optimize a global transaction involving operations on two Connections on a single JMS queue manager into a one-phase commit transaction (my research and understanding of the standards seem to indicate this isn't possible)?

我的理解如下:JMS 是一种特殊的 JCA 连接器。通常,连接器内部有一个与物理连接匹配的托管连接池。托管连接一次只能涉及一个事务(但事务可以暂停和恢复,所以稍微复杂一点)。 bean 获得的是连接句柄。如果 bean 从给定事务中获得多个连接句柄,则这些句柄由相同的托管连接支持,这意味着它不应涉及分布式事务。

当然,这取决于连接器和应用服务器的实现。实际上,您可以通过将 JMS 资源配置为非 XA (there should be an option where you can enable/disable XA support) 来尝试这一点,看看您是否可以在 MDB 中接收一条消息并将另一条消息发送到队列。它有效,这意味着不涉及分布式事务。

注意:一个常见的优化是“Last Resource Optimization”,它允许分布式事务中的参与者之一实际上是本地参与者,方法是将其用作最后一个资源。最后一个参与者永远不会意识到它属于分布式事务。

关于java - 我可以在 MDB 中获取源 JMS session 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12208733/

相关文章:

java - 如何仅在按 Enter 键或更改 JcomboBox 中的所选项目后才触发事件

java - 通过 Runtime.exec 从 Web Archive 中的 Java 代码运行命令(部署在 Jetty 中的 WAR)

java - 大型项目中监听器类的作用是什么

java - 当 servlet 的 doGet() 仍在运行时检测 J2EE 容器停止事件

java - JMS 客户端工具 - Java 8 的 HermesJMS 的替代品?

java - Spring "@Async"一次最大调用次数

java - WAS Liberty 配置文件中的 EclipseLink JPA

java - 如何更改此正则表达式以使其起作用

java - 如何在 WIldfly 8 中将 org.hornetq.ra 定义为资源适配器

jms - ActiveMQ 如何处理关闭的 session