简体   繁体   English

如何在“主”线程上运行DefaultMessageListenerContainer

[英]How to run DefaultMessageListenerContainer on the 'main' thread

I have a case where i want to run DefaultMessageListenerContainer in the same 'main' thread. 我有一种情况,我想在同一“主”线程中运行DefaultMessageListenerContainer。 Right now it uses SimpleAsyncTaskExecutor which spawns new thread every time it receives a message. 现在,它使用SimpleAsyncTaskExecutor,它在每次收到消息时都会生成新线程。

We have a test case which connects to different distributed system and do the processing and in the end it asserts few things. 我们有一个测试用例,它连接到不同的分布式系统并进行处理,最后它断言了很少的事情。 As DefaultMessageListenerContainer runs in seperate thread, main thread returns and start executing assertions before DefaultMessageListenerContainer can complete. 由于DefaultMessageListenerContainer在单独的线程中运行,因此主线程将返回并开始执行断言,直到DefaultMessageListenerContainer可以完成。 This leads to failure of the test case. 这导致测试用例失败。 As work around we have made the main thread to sleep for few seconds. 解决时,我们已使主线程休眠了几秒钟。

Sample config 样本配置

  <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" />

I am trying to use TimerTaskExecutor here because it creates single thread but that thread is seperate than main thread so problem is unresolved. 我在这里尝试使用TimerTaskExecutor,因为它创建了单线程,但是该线程与主线程是分开的,因此无法解决问题。 I tried using SyncTaskExecutor but that does not work either (or may be i dint provide the correct property value?). 我尝试使用SyncTaskExecutor,但这也不起作用(或者可能是我提供了正确的属性值?)。

Answer: 回答:
We solved this problem by using SimpleMessageListenerContainer. 我们通过使用SimpleMessageListenerContainer解决了此问题。 This is the new config 这是新的配置

     <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> 

First you must understand that is inherently asynchronous and does not block. 首先,您必须了解本质上是异步的并且不会阻塞。 This means once you send a message to a queue it will be processed by another thread, maybe on a different machine, possibly minutes or hours later if the consumer is down. 这意味着一旦您将消息发送到队列,它将由另一个线程处理,可能在另一台计算机上,如果使用者关闭,则可能在几分钟或几小时后处理。

Reading the description of your test case it looks like you are doing some system/integration testing. 阅读测试用例的描述,看起来您正在进行一些系统/集成测试。 Unfortunately there is not much you can do except waiting, however you should not wait blindly as this makes your tests slow but also not very stable - no matter how long you wait, on a busy system or some lengthy GC process your test might still time out even though there is no error. 不幸的是,除了等待之外,您无能为力,但是您不应盲目等待,因为这会使您的测试变慢,但也不会非常稳定-无论等待多长时间,在繁忙的系统上或在冗长的GC进程中,测试可能仍会计时即使没有错误也可以退出。

So instead of sleeping for a fixed number of seconds - sleep for eg ~100 milliseconds and check some condition that is only met when the processing of message was done. 因此,而不是休眠固定的秒数-休眠例如〜100毫秒,并检查某些仅在完成消息处理时才满足的条件。 For example if processing the message insert some record into the database, check the database periodically. 例如,如果处理消息将一些记录插入数据库,请定期检查数据库。

Much more elegant way (without busy waiting) is to implement request/repply pattern , see How should I implement request response with JMS? 更优雅的方式(无忙等待)是实现请求/重复模式 ,请参阅如何使用JMS实现请求响应? for implementation details. 有关实施细节。 Basically when sending a message you define a reply queue and block waiting for a message in that queue. 基本上,在发送消息时,您定义了答复队列并阻止在该队列中等待消息。 When processing the original message is done, the consumer should send a reply message to a defined queue. 处理完原始消息后,使用者应将答复消息发送到已定义的队列。 When you receive that message - perform all assertions. 当您收到该消息时-执行所有断言。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM