如何在'main'线程上运行DefaultMessageListenerContainer

时间:2012-05-07 09:18:20

标签: java spring asynchronous jms spring-integration

我有一个案例,我想在同一个'主'线程中运行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> 

2 个答案:

答案 0 :(得分:1)

首先,您必须了解本质上是异步的,并且不会阻止。这意味着一旦您向队列发送消息,它将由另一个线程处理,可能在另一台机器上处理,如果消费者关闭,可能会在几分钟或几小时后处理。

阅读测试用例的描述,看起来您正在进行一些系统/集成测试。不幸的是,除了等待之外你没有什么可以做的,但你不应该盲目等待,因为这会使你的测试变得缓慢而且也不是很稳定 - 无论你等待多久,在繁忙的系统或一些漫长的GC过程中,你的测试可能仍然是时间即使没有错误也可以。

因此,不要在固定的秒数内休眠 - 例如睡觉〜100毫秒并检查一些只在消息处理完成时才满足的条件。例如,如果处理消息将某些记录插入数据库,请定期检查数据库。

更优雅的方式(没有忙碌的等待)是实施request/repply pattern,请参阅How should I implement request response with JMS?了解实施细节。基本上,在发送消息时,您可以定义应答队列并阻止等待该队列中的消息。当处理原始消息完成时,消费者应该将回复消息发送到定义的队列。当您收到该消息时 - 执行所有断言。

答案 1 :(得分:0)

如果用于测试目的,那么一旦jms活动完成,为什么不使用运行断言的CyclicBarrier。