保持spring上下文有效,直到消耗JMS消息

Mil*_*nov 14 java activemq-classic jms spring-boot

我有一个非常标准的设置JMS- Spring BootActiveMQ.它工作正常,直到我尝试进行简单的集成测试.经过一些调查后,我发现在第一个JMS消息被消耗后,Spring上下文和嵌入式代理都被关闭,无论消费过程中是什么,都会触发另一个事件.经纪人问题我能够通过useShutdownHook=false在测试设置中添加连接选项来解决,即

spring.activemq.broker-url = vm://broker?async=false&broker.persistent=false&broker.useShutdownHook=false
Run Code Online (Sandbox Code Playgroud)

我正在寻找的基本上是一种强制测试"保持活力"的方法,直到消耗掉所有JMS消息(在这种情况下它们只是两个).我理解整个设置的异步性质,但是在测试期间,生成和使用这些消息的所有结果会很有帮助.

下面是我的设置,虽然它很简单.

@EnableJms
public class ActiveMqConfig {

    @Bean
    public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {
        JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
        jmsTemplate.setMessageConverter(messageConverter);
        return jmsTemplate;
    }

    @Bean
    public MessageConverter messageConverter() {
        MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
        messageConverter.setTargetType(MessageType.TEXT);
        messageConverter.setTypeIdPropertyName("_type");
        return messageConverter;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个消息驱动的POJO,它监听给定的事件:

@JmsListener(destination = "events")
public void applicationSubmitted(MyType event) {
    // do some work with the event here

    jmsTemplate.convertAndSend("commands", mymessage);
}
Run Code Online (Sandbox Code Playgroud)

还有一个:

@JmsListener(destination = "commands")
public void onCommand(TextMessage textMessage) {

}
Run Code Online (Sandbox Code Playgroud)

我试过的一件事就是添加一个延迟,即sleep(200)在发送消息之后.然而,这是非常不可靠的,也会减慢测试速度,因为执行可能需要不到50毫秒.以下是测试本身.除非等待取消注释,否则我永远不会进入第二个事件监听器,因为应用程序上下文关闭,测试结束并且消息被"遗忘".

@SpringBootTest
class MyEventIntegrationTest extends Specification {

    @Autowired
    JmsTemplate jmsTemplate

    def "My event is successfully handled"() {

        given:
        def event = new MyEvent()

        when:
        jmsTemplate.convertAndSend("events", event)
        // sleep(200)

        then:
        1 == 1
    }
}
Run Code Online (Sandbox Code Playgroud)

Tho*_*rig 3

我认为你的问题的根源是异步事件处理。发送事件后,您的测试就结束了。当然,这将导致 Spring 上下文和代理关闭。JMS 侦听器正在另一个线程中运行。你必须想办法等待他们。否则,您的线程(即您的测试用例)就刚刚完成。

我们在上一个项目中遇到了类似的问题,并编写了一个小实用程序,这对我们有很大帮助。JMS 提供“浏览”队列并查看队列是否为空的功能:

public final class JmsUtil {

    private static final int MAX_TRIES = 5000;
    private final JmsTemplate jmsTemplate;

    public JmsUtil(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    private int getMessageCount(String queueName) {
        return jmsTemplate.browseSelected(queueName, "true = true", (s, qb) -> Collections.list(qb.getEnumeration()).size());
    }

    public void waitForAll(String queueName) {
        int i = 0;
        while (i <= MAX_TRIES) {
            if (getMessageCount(queueName) == 0) {
                return;
            }
            i++;
        }
}
Run Code Online (Sandbox Code Playgroud)

使用这个实用程序,您可以执行以下操作:

def "My event is successfully handled"() {

        given:
        def event = new MyEvent()

        when:
        jmsTemplate.convertAndSend("events", event)
        jmsUtility.waitForAll("events"); // wait until the event has been consumed
        jmsUtility.waitForAll("commands"); // wait until the command has been consumed

        then:
        1 == 1
    }
Run Code Online (Sandbox Code Playgroud)

注意:此实用程序假定您将 JMS 消息发送到队列。通过浏览队列我们可以检查它是否为空。如果是某个主题,您可能需要进行另一次检查。所以要注意这一点!