这个问题主要集中在使用 Websphere MQ (WMQ) 时的 Websphere Application Server (WAS),因为这是我最熟悉的。但是,我认为我所说的一切更普遍地适用于所有 Java EE 应用程序服务器,因为我坚持使用 Java 标准接口。我更喜欢与标准相关的解释,但我仍然会对特定于 WAS/WMQ 的答案感到非常兴奋。
JMS 1.1 为 JMS 定义了一种与应用服务器交互的机制。粗略的过程是在某个时候创建 ConnectionConsumer 来监视队列或主题。当消息出现时,JMS 实现从 ServerSessionPool 中获取一个 ServerSession 对象,将消息加载到与 ServerSession 关联的 Session 中,然后在 ServerSession 对象上调用 start()。然后,ServerSession 负责调度消息以供 MDB 在应用程序服务器线程上处理。MDB 将消息作为其 onMessage() 方法的一部分来获取,并且可以执行它需要的任何处理。
这一切都很好,直到 MDB 决定它想要发送另一条消息来响应它收到的消息。为此,MDB 必须查找或注入 ConnectionFactory 对象,获取 Connection,然后是 Session,然后是 MessageProducer,最后发送消息。这一切似乎都很浪费。作为向 MDB 传递消息的一部分,已经创建了 Connection 和 Session 对象。如果 MDB 能够以某种方式访问该会话,它就可以避免必须做所有这些额外的工作并避免必须创建所有这些额外的连接。作为成本的额外工作 - 为了只向请求消息发送回复消息,MDB 必须使用两个连接和两个会话(每个会话用于获取消息并发送响应)。使用全局事务时,我相信这迫使应用程序服务器将事务处理为两阶段提交事务(至少一些,如果不是全部,应用程序服务器可以通过将其处理为一阶段提交来优化仅涉及单个资源的全局事务) . 使事务成为两阶段事务显着增加了处理消息的开销,并且还引入了各种新的复杂性(不确定事务是最大的事务之一)。
JMS 1.1 规范指出:“由于许多侦听器将需要使用其会话的服务,因此侦听器可能要求将其会话作为构造函数参数传递给它”,这似乎表明它完全可以接受MDB 使用传递初始消息的会话也发送响应。但是,我不知道以标准方式从 MDB 检索此 Session 对象的任何机制。我也不知道以非标准方式检索它的任何机制。我什至在任何地方都找不到关于此的问题或博客文章。
所以,问题是:为什么会这样?JMS API 相当复杂,但是,我看不出其中有任何东西会使 MDB 难以使用为它提供原始消息的 Session 来发送响应(如果它可以访问它)。MDB 不能使用这个 Session 对象有什么原因吗?是否有符合标准的方法来访问会话?有不符合标准的方法吗?应用程序服务器/JMS 实现是否可以智能地将涉及单个 JMS 队列管理器上的两个连接上的操作的全局事务优化为单阶段提交事务(我对标准的研究和理解似乎表明这是不可能的)?