我有一个类,它本质上消耗JMS消息,然后用这些消息调用闭包。消息侦听器在一个单独的线程中运行。
import groovy.util.logging.Slf4j
import javax.jms.*
@Slf4j
class JMSProducer {
Connection connection
List<Queue> queues
private Session session
private List<MessageConsumer> messageConsumers
@Override
void init() {
connection.start()
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)
messageConsumers = queues.collect { session.createConsumer(it) }
}
@Override
void produce(final Closure closure) {
def listener = new MessageListener() {
@Override
void onMessage(Message message) {
if (message instanceof ObjectMessage) {
try {
log.info("Calling");
closure.call(message.object);
log.info("Called");
} catch(e) {
log.error("Error")
} finally {
log.info("Finally");
}
} else {
log.error("Unrecognized message")
}
}
}
messageConsumers.each {
it.messageListener = listener
}
}
}
上面代码的问题是,对于我放入队列的所有消息,我都会看到"Calling"、"Called"one_answers"Finally",但闭包本身只调用了其中的一小部分。
//Assume 5 messages have been put into queue, and
// JMSProducer has been configured to read from queue*
new JMSProducer().produce { message ->
log.info("Received Message");
}
"Received Message"只记录两次(尽管我看到"Calling"/"Called"/"Finally"各五次)。
就好像闭包被忽略或跳过了一样。
当我在IDE中运行这个时,我没有这个问题,只有在运行./gradlew clean test
。
最终,这看起来像是一个竞争条件,但我不知道如何在闭包执行之前和之后进行日志记录,也看不到应该在闭包内部进行的日志记录。
作为更新,我添加了在运行时注销闭包对象的代码,我看到了以下输出(代码在调试中略有更改,但问题仍然存在):
2016-01-12 14:56:04 INFO JMSProducer - Calling: StreamUtil$2@1edef6f9
2016-01-12 14:56:04 INFO JMSProducer - Calling:JMSProducerTest$_verifyJMSProducer_closure1@fa11e9d
2016-01-12 14:56:04 INFO JMSProducer - Called
2016-01-12 14:56:04 INFO JMSProducer - Finally
2016-01-12 14:56:04 INFO JMSProducer - Called
2016-01-12 14:56:04 INFO JMSProducer - Finally
2016-01-12 14:56:04 INFO JMSProducer - Calling: StreamUtil$2@1edef6f9
2016-01-12 14:56:04 INFO JMSProducer - Calling: JMSProducerTest$_verifyJMSProducer_closure1@fa11e9d
2016-01-12 14:56:04 INFO JMSProducer - Called
2016-01-12 14:56:04 INFO JMSProducer - Finally
2016-01-12 14:56:04 INFO JMSProducer - Called
2016-01-12 14:56:04 INFO JMSProducer - Finally
2016-01-12 14:56:04 INFO JMSProducer - Calling: JMSProducerTest$_verifyJMSProducer_closure1@fa11e9d
2016-01-12 14:56:04 INFO JMSProducer - Called
2016-01-12 14:56:04 INFO JMSProducer - Finally
回调似乎不是一回事。只有当我得到StreamUtil$2@1edef6f9时,回调才会执行。
好的,所以JMS中显然存在竞争条件,并且之前的测试能够以某种方式覆盖消息侦听器(但仅用于部分迭代)。不完全确定这是如何发生的,但这与异步测试和JUnit有关。