【问题标题】:How to catch when JMS connection is established?JMS 连接建立时如何捕捉?
【发布时间】:2013-04-18 23:25:23
【问题描述】:

我有消息生产者使用 ActiveMQ 发送有关某些事件的 JMS 消息。 但是,与 ActiveMQ 的连接可能不会一直处于打开状态。因此,事件被存储,当连接建立时,它们应该被读取和发送。这是我的代码:

private void sendAndSave(MyEvent event) {
    boolean sent = sendMessage(event);
    event.setProcessed(sent);
    boolean saved = repository.saveEvent(event);
    if (!sent && !saved) {
        logger.error("Change event lost for Id = {}", event.getId());
    }
}

private boolean sendMessage(MyEvent event) {
    try {
        messenger.publishEvent(event);
        return true;
    } catch (JmsException ex) {
        return false;
    }
}

我想创建某种类型的 ApplicationEventListener,在建立连接并处理未发送事件时将调用它。 我浏览了 JMS、Spring 框架和 ActiveMQ 文档,但找不到任何线索如何将我的侦听器与 ConnectionFactory 连接起来。

如果有人可以帮助我,我将不胜感激。

这是我的应用程序 Spring 上下文对 JMS 的评价:

<!-- Connection factory to the ActiveMQ broker instance.              -->
<!-- The URI and credentials must match the values in activemq.xml    -->
<!-- These credentials are shared by ALL producers.                   -->
<bean id="jmsTransportListener" class="com.rhd.ams.service.common.JmsTransportListener" 
      init-method="init" destroy-method="cleanup"/>
<bean id="amqJmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
    <property name="brokerURL" value="${jms.publisher.broker.url}"/>
    <property name="userName" value="${jms.publisher.username}"/>
    <property name="password" value="${jms.publisher.password}"/>
    <property name="transportListener" ref="jmsTransportListener"/>
</bean>

<!-- JmsTemplate, by default, will create a new connection, session, producer for         -->
<!-- each message sent, then close them all down again. This is very inefficient!         -->
<!-- PooledConnectionFactory will pool the JMS resources. It can't be used with consumers.-->
<bean id="pooledAmqJmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
    <property name="connectionFactory" ref="amqJmsConnectionFactory" />
</bean>

<!-- Although JmsTemplate instance is unique for each message, it is  -->
<!-- thread-safe and therefore can be injected into referenced obj's. -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <constructor-arg ref="pooledAmqJmsConnectionFactory"/>
</bean>

【问题讨论】:

  • 您需要详细说明您的设置。您是否使用故障转移传输等?
  • 我已将 Spring 应用上下文添加到我的原始消息中。
  • 这仍然无用,因为它省略了连接 U​​RI。

标签: java jms activemq


【解决方案1】:

按照您描述问题的方式,这听起来确实像是 JMS 持久订阅的一个打开和关闭的案例。在走这条路之前,您可能需要考虑更传统的实现。抛开注意事项不谈,ActiveMQ 提供了Advisory Messages,您可以收听它并将其发送给包括新连接在内的各种事件。

=========

射击,对不起...我不明白问题出在哪里。我认为咨询根本不是解决方案....毕竟,您需要连接到经纪人才能获得它们,但连接是您所知道的。

所以如果我理解正确(准备重试 #2....),您需要的是一个客户端连接,当它失败时,它会尝试无限期地重新连接。当它重新连接时,您希望触发一个(或更多)事件,将挂起的消息刷新到代理。

因此检测丢失的连接很容易。您只需注册一个 JMS ExceptionListener。至于检测重新连接,我能想到的最简单的方法是启动重新连接线程。当它连接时,停止重新连接线程并使用 Observer/Observable 或 JMX 通知等通知相关方。您可以使用ActiveMQ Failover Transport,它将为您执行连接重试循环,即使您只有一个代理。至少,它是supposed to,但它并没有为你做那么多,你自己的重新连接线程无法完成...... 但是如果你愿意将一些控制权委托给它,它会缓存您未刷新的消息(请参阅 trackMessages 选项),然后在重新连接时发送它们,这就是您尝试做的所有事情。

我想如果你的代理宕机了几分钟,这不是一个坏方法,但如果你是几个小时,或者你可能会在宕机时间内积累 10k+ 条消息,我只是不知道那个缓存是否机制与您需要的一样可靠。

==================

移动应用程序...对。不太适合故障转移传输。然后我会实现一个定期连接的计时器(使用http传输可能是个好主意,但不相关)。当它确实连接时,如果没有什么要冲洗的,那么在 x 分钟内见。如果有,请发送每条消息,等待握手并从您的移动商店中清除该消息。然后在 x 分钟后再见。

我认为这是 Android 吗?如果没有,请停止阅读此处。我们实际上在前段时间实现了这一点。我只做了服务器端,但如果我没记错的话,连接计时器/轮询器每 n 分钟旋转一次(我认为是可变频率,因为过于激进会耗尽电池电量)。一旦建立成功的连接,我相信他们使用意图广播来推动消息推送者做他们的事情。当时的想法是,即使只有一个消息推送器,我们也可以添加更多。

【讨论】:

  • 它看起来不像 JMS Durable 订阅。根据持久订阅消息的定义,订阅者可能远离 JMS 连接,当他们最终连接时,他们将收到这些消息。在我的情况下,消息生产者可能会丢失 JMS 连接,但会存储所有生成的消息。当它连接时,它需要发送所有未发送的消息。关于 ActiveMQ 咨询支持,它可能是一个解决方案,但我无法找出 CONNECTION_ADVISORY_TOPIC 消息携带的信息。谷歌搜索没有帮助。你知道任何代码示例吗?
  • 如果我要创建自己的重新连接循环,它会干扰 ActiveMQ 故障转移传输,不是吗?如果 ActiveMQ 故障转移传输处理重试循环,如何通知我的应用程序重新建立连接? ActiveMQ 故障转移传输提供的缓存大小太小。我的客户端是一个移动应用程序,可以离开 WIFI 几个小时。我将未发送的事件存储在磁盘上。
猜你喜欢
  • 1970-01-01
  • 2015-09-12
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-08
  • 1970-01-01
  • 2013-06-01
相关资源
最近更新 更多