ActiveMQ CMS:在创建使用者和设置侦听器之间是否会丢失消息?

问题描述

使用侦听器设置CMS使用者涉及两个单独的调用:首先,获得使用者:

 cms::MessageConsumer* cms::Session::createConsumer( const cms::Destination* );

然后在使用者上设置一个侦听器:

void cms::MessageConsumer::setMessageListener( cms::MessageListener* );

如果实现在侦听器被激活之前订阅了目的地(并从代理/路由器接收消息),消息是否会丢失?还是这些消息在内部排队并在激活后传递给侦听器?

为什么没有API调用来使用监听器作为构造参数来创建使用者? (是因为JMS规范没有它?)

(附录:这可能是API本身的缺陷。更合乎逻辑的顺序是从会话实例化使用者,并在API中使用cms::Consumer::subscribe( cms::Destination*,cms::MessageListener* )方法。)

解决方法

我认为API不一定存在缺陷。显然可以用其他方法设计它,但是我相信您所称问题的解决方案来自start对象(通过Connection继承)上的Startable方法。 Connection的文档指出:

CMS客户端通常创建一个连接,一个或多个会话以及许多消息生产者和使用者。创建连接后,它处于停止模式。这意味着没有邮件被传递。

通常将连接保持在停止模式,直到设置完成(即,直到创建了所有消息使用者)为止。此时,客户端调用连接的start方法,并且消息开始到达连接的使用者。该设置约定最大程度地减少了客户端仍在设置自身过程中由于异步消息传递而引起的任何客户端混乱。

可以立即开始连接,然后可以进行设置。这样做的客户端必须准备好在仍处于设置过程中处理异步消息传递。

这与JMS遵循的模式相同。

无论如何,无论何时调用start(),我都认为没有消息丢失的风险。如果使用者使用自动确认模式,则只有通过一种接收方法同步传递消息或通过侦听器的onMessage异步传递消息后,才应自动确认消息。否则,这将是我估计的错误。在过去的10年中,我一直与JMS一起进行各种实现,但从未见过与此有关的消息丢失的任何情况。

如果您想在调用start()之后添加使用者,则可以肯定先调用stop(),但是我认为在运行中简单地添加使用者没有任何问题。