将消息从本地代理传递到已被中断的中央代理

时间:2016-09-02 09:57:13

标签: java spring jms activemq spring-jms

我有一个特定的要求,我需要将消息发送到一个永远不可用的服务器。

为此,我使用了一个特定于ActiveMQ的经纪人网络。

目标是拥有一个本地应用程序A(仅限生产者),它将消息推送到另一个中央应用程序B(仅限消费者)。然而,网络永远不可用。因此,应用程序的代理必须存储消息并等待连接才能向应用程序B发送消息。所以基本上A是需要在消息可用时将消息转发给B的代理

Broker的B配置包括一个持久的主题,它正在监听以消费消息。

正如在ActiveMQ documentation中所说的,我必须使用静态网桥来实现这一点,这就是我所做的。

注意:我无法订阅A,因为A会有多个实例,我无法在B中配置所有实例。

所以这是本地应用程序的配置(原始弹簧):

<!--As said in http://activemq.apache.org/spring-support.html use 
    a pooled conntection along with JMSTemplate -->
 <amq:connectionFactory id="jmsFactory" brokerURL="${jms.broker.local.url}" />
<!--SpringJMSTemplate -->
<bean id="myJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="jmsFactory" />
</bean>
<!-- local broker with embedded -->
<bean id="localbroker" class="org.apache.activemq.broker.BrokerService"
    init-method="start" destroy-method="stop">
    <property name="brokerName" value="localBroker" />
    <property name="transportConnectorURIs">
        <list>
            <value>${jms.broker.local.url}</value>
        </list>
    </property>
    <property name="networkConnectors">
        <list>
            <ref bean="networkConnector" />
        </list>
    </property>
</bean>

<amq:connectionFactory id="remoteJmsFactory"
    brokerURL="${jms.broker.remote.url}" clientIDPrefix="BRIDGED-TEST" />

<bean id="networkConnector" class="org.apache.activemq.network.DiscoveryNetworkConnector">
    <property name="uri" value="static:(${jms.broker.remote.url})"></property>
    <property name="staticallyIncludedDestinations">
        <list>
            <bean class="org.apache.activemq.command.ActiveMQTopic">
                <constructor-arg type="java.lang.String" value="${jms.topic.sample}"/>
            </bean>
        </list>
    </property>
    <property name="staticBridge" value="true"></property><!-- will deliver content even if no consumer, usefull for durable topic only -->
</bean>

localbroker是连接到远程代理的嵌入式代理(可以从apacheMQ页面下载的应用程序)。

这是中央配置

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <value>file:${activemq.conf}/credentials.properties</value>
    </property>
</bean>


<bean id="logQuery" class="io.fabric8.insight.log.log4j.Log4jLogQuery"
      lazy-init="false" scope="singleton"
      init-method="start" destroy-method="stop">
</bean>

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" useVirtualDestSubs="true">

    <destinationPolicy>
        <policyMap>
          <policyEntries>
            <policyEntry topic=">" >
              <pendingMessageLimitStrategy>
                <constantPendingMessageLimitStrategy limit="1000"/>
              </pendingMessageLimitStrategy>
            </policyEntry>
          </policyEntries>
        </policyMap>
    </destinationPolicy>
    <managementContext>
        <managementContext createConnector="false"/>
    </managementContext>
    <persistenceAdapter>
        <kahaDB directory="${activemq.data}/kahadb"/>
    </persistenceAdapter>
      <systemUsage>
        <systemUsage>
            <memoryUsage>
                <memoryUsage percentOfJvmHeap="70" />
            </memoryUsage>
            <storeUsage>
                <storeUsage limit="100 gb"/>
            </storeUsage>
            <tempUsage>
                <tempUsage limit="50 gb"/>
            </tempUsage>
        </systemUsage>
    </systemUsage>
    <transportConnectors>
        <transportConnector name="http" uri="http://0.0.0.0:61612?maximumConnections=1000&amp;wireFormat.maxFrameSize=10485760"/>
    </transportConnectors>
    <shutdownHooks>
        <bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
    </shutdownHooks>

</broker>
<import resource="jetty.xml"/>

当我尝试发送/接收消息时发生了什么:

  • 如果生产者(A)已连接且消费者(B)连接到其各自的经纪人,并且经纪人连接在一起,则工作正常。
  • 如果消费者(B)连接到他的经纪人并且有消息未决,而生产者A的经纪人断开连接,则工作正常。
  • 如果制作人(A)与网络断开连接,那么当B再次可用时,A的经纪人不会将该消息传递给B的经纪人。

在网络连接器之前,我在本地代理配置中使用outboundTopicBridge尝试了jmsbridgeConnector而没有任何运气。

这是一个问题:我如何让本地经纪人A在重新连接时向中央经纪人B发送消息。虽然它不可用,但请确保他不会丢失任何信息。

注意:

  • 我工作的网络不是可用的(可以是!),我只能依赖http端口,这就是为什么它是唯一一个打开的网络。这意味着无法进行多播发现。
  • 邮件必须只发送一次。
  • 我使用本地经纪人的原因是不管理我必须自己发送的内容。他们现在只是用来存储和转发到中央。
编辑:我已经能够使用JMS Bridge工作,但是我有最后一个问题,如果连接在应用程序启动或应用程序生命周期中丢失,我需要重启我的代理才能发送消息。

2 个答案:

答案 0 :(得分:0)

我一直在使用这种“存储转发”模式并成功使用网桥。

我无法评论网络连接器,但对于网桥,您必须:

  • 使用Bug AMQ-5859
  • 的最新版本的jmeter
  • 在网桥上添加org.apache.activemq.network.jms.ReconnectionPolicy
  • 确保在远程代理连接工厂
  • 上设置reconnectOnException

答案 1 :(得分:0)

我已经尝试过一直使用配置无法让它工作,所以我最终自己这样做了:

WKWebView

             

<jms:listener-container container-type="default" factory-id="proxyFactory"
    acknowledge="transacted" destination-type="topic" connection-factory="jmsFactory">

基本上我只有一个订阅具有持久订阅的本地代理的类,并向远程发送消息,如果失败,则会回滚会话。

这个简单的代理依赖于Spring Listener的容器,因此即使他在远程代理上监听也可能工作,在我的情况下,它正在监听本地嵌入式代理,所以我不会有任何问题。 / p>

如果其他人在本地应用程序处于停止状态并且不需要重新启动来发送消息时停止/启动远程代理时只有其他配置应答,请随时发布,我将进行upvote并检查。< / p>

注意:您必须将<bean id="remoteJmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="remoteJmsFactory" /> <property name="pubSubDomain" value="true"/> </bean> <bean id="simpleMessageProxyListener" class="com.xxx.jms.test.SimpleMessageProxyListener"> <property name="jmsTemplate" ref="remoteJmsTemplate" /> <property name="queueName" value="${jms.topic.sample}" /> </bean> 设置为jms.redeliveryPolicy.maximumDeliveries才能使其正常运行。