Activemq 消息驱动通道适配器在应用程序上下文启动后丢弃第一条消息,除非延迟调用send
我有一个针对Spring集成配置的集成测试,它使用来自JMS主题的消息和持久订阅。对于测试,我使用ActiveMQ而不是Tibco EMS。 我遇到的问题是,在测试方法开始时,我必须使用睡眠调用延迟向端点发送第一条消息。否则,消息将被丢弃。 如果我删除持久订阅和选择器的设置,那么第一条消息可以立即发送,不会有延迟。 我想摆脱不可靠的睡眠。在发送消息之前,是否有方法检查端点是否已完全设置? 下面是配置 谢谢你的帮助Activemq 消息驱动通道适配器在应用程序上下文启动后丢弃第一条消息,除非延迟调用send,activemq,spring-integration,spring-jms,Activemq,Spring Integration,Spring Jms,我有一个针对Spring集成配置的集成测试,它使用来自JMS主题的消息和持久订阅。对于测试,我使用ActiveMQ而不是Tibco EMS。 我遇到的问题是,在测试方法开始时,我必须使用睡眠调用延迟向端点发送第一条消息。否则,消息将被丢弃。 如果我删除持久订阅和选择器的设置,那么第一条消息可以立即发送,不会有延迟。 我想摆脱不可靠的睡眠。在发送消息之前,是否有方法检查端点是否已完全设置? 下面是配置 谢谢你的帮助 <int-jms:message-driven-channel-ad
<int-jms:message-driven-channel-adapter
id="myConsumer" connection-factory="myCachedConnectionFactory"
destination="myTopic" channel="myChannel" error-channel="errorChannel"
pub-sub-domain="true" subscription-durable="true"
durable-subscription-name="testDurable"
selector="..."
transaction-manager="emsTransactionManager" auto-startup="false"/>
如果您使用干净的嵌入式activemq进行测试,则在建立订阅之前,订阅的持久性是无关的。所以你别无选择,只能等到那一刻 您可以通过发送一系列启动消息来避免睡眠,并且只在收到最后一条消息时启动真正的测试 编辑 我忘了在
DefaultMessageListenerContainer
上有一个方法isRegisteredWithDestination()
Javadocs
/**
* Return whether at least one consumer has entered a fixed registration with the
* target destination. This is particularly interesting for the pub-sub case where
* it might be important to have an actual consumer registered that is guaranteed
* not to miss any messages that are just about to be published.
* <p>This method may be polled after a {@link #start()} call, until asynchronous
* registration of consumers has happened which is when the method will start returning
* {@code true} – provided that the listener container ever actually establishes
* a fixed registration. It will then keep returning {@code true} until shutdown,
* since the container will hold on to at least one consumer registration thereafter.
* <p>Note that a listener container is not bound to having a fixed registration in
* the first place. It may also keep recreating consumers for every invoker execution.
* This particularly depends on the {@link #setCacheLevel cache level} setting:
* only {@link #CACHE_CONSUMER} will lead to a fixed registration.
*/
您必须共享用于测试的测试用例和整个配置。您可能真的很早就发送了一条消息,并且只在发送之后执行Subscription,所以我看到auto startup=false。如果你在发送消息后将其切换为true,这可能会产生影响。我希望有一种不同于发送实际消息的方式。请参阅我答案的编辑。顺便说一句,您不应该在新答案中添加澄清,而应该编辑您的问题。我使用的条件“amqBroker.getRegionBroker().getDestinationMap().containsKey(myTopic)”似乎有效,而不是使用isRegisteredWithDestination()。amqBroker是BrokerService bean。
/**
* Blocks until the listener container has subscribed; if the container does not support
* this test, or the caching mode is incompatible, true is returned. Otherwise blocks
* until timeout milliseconds have passed, or the consumer has registered.
* @see DefaultMessageListenerContainer#isRegisteredWithDestination()
* @param timeout Timeout in milliseconds.
* @return True if a subscriber has connected or the container/attributes does not support
* the test. False if a valid container does not have a registered consumer within
* timeout milliseconds.
*/
private static boolean waitUntilRegisteredWithDestination(SubscribableJmsChannel channel, long timeout) {
AbstractMessageListenerContainer container =
(AbstractMessageListenerContainer) new DirectFieldAccessor(channel).getPropertyValue("container");
if (container instanceof DefaultMessageListenerContainer) {
DefaultMessageListenerContainer listenerContainer =
(DefaultMessageListenerContainer) container;
if (listenerContainer.getCacheLevel() != DefaultMessageListenerContainer.CACHE_CONSUMER) {
return true;
}
while (timeout > 0) {
if (listenerContainer.isRegisteredWithDestination()) {
return true;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) { }
timeout -= 100;
}
return false;
}
return true;
}