我有一个案例,我想在同一个'主'线程中运行DefaultMessageListenerContainer。现在它使用SimpleAsyncTaskExecutor,每次收到消息时都会生成新线程。
我们有一个连接到不同分布式系统的测试用例并进行处理,最后它断言了一些事情。由于DefaultMessageListenerContainer在单独的线程中运行,因此主线程在DefaultMessageListenerContainer完成之前返回并开始执行断言。这导致测试用例失败。作为解决方法,我们让主线程休眠几秒钟。
示例配置
<int-jms:message-driven-channel-adapter
id="mq.txbus.publisher.channel.adapter"
container="defaultMessageListenerContainer"
channel="inbound.endpoint.publisher"
acknowledge="transacted"
extract-payload="true" />
<beans:bean id="defaultMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<beans:property name="connectionFactory" ref="mockConnectionFactory"/>
<beans:property name="destination" ref="publisherToTxmQueue"/>
<beans:property name="taskExecutor" ref="taskExecutor"/>
<beans:property name="maxMessagesPerTask" value="10"/>
<beans:property name="sessionTransacted" value="true"/>
</beans:bean>
<beans:bean id="taskExecutor" class="org.springframework.scheduling.timer.TimerTaskExecutor" />
我试图在这里使用TimerTaskExecutor,因为它创建了单个线程,但该线程与主线程分离,因此问题尚未解决。我尝试过使用SyncTaskExecutor,但这也不起作用(或者我可以提供正确的属性值吗?)。
答案:
我们使用SimpleMessageListenerContainer解决了这个问题。
这是新的配置
<int-jms:message-driven-channel-adapter
id="mq.txbus.publisher.channel.adapter"
container="messageListenerContainer"
channel="inbound.endpoint.publisher"
acknowledge="transacted"
extract-payload="true" />
<beans:bean id="messageListenerContainer" class="org.springframework.jms.listener.SimpleMessageListenerContainer">
<beans:property name="connectionFactory" ref="mockConnectionFactory"/>
<beans:property name="destination" ref="publisherToTxmQueue"/>
<beans:property name="sessionTransacted" value="true"/>
<beans:property name="exposeListenerSession" value="false"/>
</beans:bean>
答案 0 :(得分:1)
首先,您必须了解jms本质上是异步的,并且不会阻止。这意味着一旦您向队列发送消息,它将由另一个线程处理,可能在另一台机器上处理,如果消费者关闭,可能会在几分钟或几小时后处理。
阅读测试用例的描述,看起来您正在进行一些系统/集成测试。不幸的是,除了等待之外你没有什么可以做的,但你不应该盲目等待,因为这会使你的测试变得缓慢而且也不是很稳定 - 无论你等待多久,在繁忙的系统或一些漫长的GC过程中,你的测试可能仍然是时间即使没有错误也可以。
因此,不要在固定的秒数内休眠 - 例如睡觉〜100毫秒并检查一些只在消息处理完成时才满足的条件。例如,如果处理消息将某些记录插入数据库,请定期检查数据库。
更优雅的方式(没有忙碌的等待)是实施request/repply pattern,请参阅How should I implement request response with JMS?了解实施细节。基本上,在发送消息时,您可以定义应答队列并阻止等待该队列中的消息。当处理原始消息完成时,消费者应该将回复消息发送到定义的队列。当您收到该消息时 - 执行所有断言。
答案 1 :(得分:0)
如果用于测试目的,那么一旦jms活动完成,为什么不使用运行断言的CyclicBarrier。