当 Tomcat 管理器发出“停止”命令时,我们的系统不会关闭。我已确定与ActiveMQ/Spring有关。我什至已经弄清楚如何让它关闭,但是我的解决方案是一个黑客(至少我希望这不是“正确”的方法)。我想知道关闭 ActiveMQ 的正确方法,以便我可以删除我的 hack。
我继承了这个组件,但我不知道为什么要做出某些架构决策,经过大量挖掘后,我想我理解了他的想法,但我可能会遗漏一些东西。换句话说,真正的问题可能在于我们尝试使用 ActiveMQ/Spring 的方式。
我们在 ServletContainer (Tomcat 6/7) 中运行并使用 ActiveMQ 5.9.1 和 Spring 3.0.0 我们的应用程序的多个实例可以在一个“组”中运行,每个实例都在其自己的服务器上运行。 ActiveMQ 用于促进多个实例之间的通信。每个实例都有自己的嵌入式代理和自己的一组队列。每个实例上的每个队列都有 1 个 org.springframework.jms.listener.DefaultMessageListenerContainer 监听它,因此 5 个队列 = 5 个 DefaultMessageListenerContainer。
我们的系统正常关闭,直到我们通过向 ConnectionFactory 添加queuePrefetch =“0”来修复错误。起初我认为这个更改在某种程度上是不正确的,但现在我了解了情况,我确信我们不应该使用预取功能。
我创建了一个测试应用程序来复制该问题。请注意,下面的信息没有提及消息生产者。这是因为我可以复制该问题,而无需发送/处理一条消息。只需在启动期间创建 Broker、ConnectionFactory、Queues 和 Listeners,就足以防止系统正常停止。
这是我的 Spring XML 中的示例配置。如果有人需要,我很乐意提供我的整个项目:
<amq:broker persistent="false" id="mybroker">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://0.0.0.0:61616"/>
</amq:transportConnectors>
</amq:broker>
<amq:connectionFactory id="ConnectionFactory" brokerURL="vm://localhost?broker.persistent=false" >
<amq:prefetchPolicy>
<amq:prefetchPolicy queuePrefetch="0"/>
</amq:prefetchPolicy>
</amq:connectionFactory>
<amq:queue id="lookup.mdb.queue.cat" physicalName="DogQueue"/>
<amq:queue id="lookup.mdb.queue.dog" physicalName="CatQueue"/>
<amq:queue id="lookup.mdb.queue.fish" physicalName="FishQueue"/>
<bean id="messageListener" class="org.springframework.jms.listener.DefaultMessageListenerContainer" abstract="true">
<property name="connectionFactory" ref="ConnectionFactory"/>
</bean>
<bean parent="messageListener" id="cat">
<property name="destination" ref="lookup.mdb.queue.dog"/>
<property name="messageListener">
<bean class="com.acteksoft.common.remote.jms.WorkerMessageListener"/>
</property>
<property name="concurrentConsumers" value="200"/>
<property name="maxConcurrentConsumers" value="200"/>
</bean>
<bean parent="messageListener" id="dog">
<property name="destination" ref="lookup.mdb.queue.cat"/>
<property name="messageListener">
<bean class="com.acteksoft.common.remote.jms.WorkerMessageListener"/>
</property>
<property name="concurrentConsumers" value="200"/>
<property name="maxConcurrentConsumers" value="200"/>
</bean>
<bean parent="messageListener" id="fish">
<property name="destination" ref="lookup.mdb.queue.fish"/>
<property name="messageListener">
<bean class="com.acteksoft.common.remote.jms.WorkerMessageListener"/>
</property>
<property name="concurrentConsumers" value="200"/>
<property name="maxConcurrentConsumers" value="200"/>
</bean>
我的黑客涉及使用 ServletContextListener 手动停止对象。棘手的部分是我必须创建额外的线程来停止 DefaultMessageListenerContainers。也许我以错误的顺序停止了对象,但我已经尝试了我能想象到的一切。如果我尝试停止主线程中的对象,那么它们将无限期地挂起。
先感谢您!
UPDATE我根据身体的建议尝试了以下方法,但没有成功。我还尝试将 amq:transportConnector uri 指定为 tcp://0.0.0.0:61616?transport.daemon=true
<amq:broker persistent="false" id="mybroker" brokerName="localhost">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://0.0.0.0:61616?daemon=true"/>
</amq:transportConnectors>
</amq:broker>
<amq:connectionFactory id="connectionFactory" brokerURL="vm://localhost" >
<amq:prefetchPolicy>
<amq:prefetchPolicy queuePrefetch="0"/>
</amq:prefetchPolicy>
</amq:connectionFactory>
有一次,我尝试向 amq:connectionFactory 元素中的brokerUrl 参数添加类似的属性,并且关闭工作正常,但是经过进一步测试,我了解到这些属性导致从 VMTransportFactory 抛出异常。这导致初始化不正确并且基本消息功能无法工作。