如何防止 Spring JmsTemplate 单元测试在读取 ActiveMQ 队列时阻塞?

How can I prevent Spring JmsTemplate unit test from blocking when reading ActiveMQ queue?

如何防止 Spring JmsTemplate unit test sendAndReceivePerson() from blocking when attempting to read a Person object from ActiveMQ 排队 person.queue

测试创建一个 Person 对象,将其发送到队列 person.queue(这也应该创建包含该队列的嵌入式代理),然后尝试从同一个队列中读取该对象.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MessagingConfiguration.class})
public class PersonMessengerTest {
    @Autowired
    private PersonMessenger personMessenger;

    @Test
    public void sendAndReceivePerson() {
        final Person person = new Person();
        final UUID id = UUID.randomUUID();
        person.setId(id);
        person.setFirstName("Derek");
        person.setLastName("Mahar");
        personMessenger.sendPersion(person);
        final Person receivedPersion = personMessenger.receivePersion();
        assertEquals(id, receivedPersion.getId());
    }
}

public class PersonMessenger {

    private final JmsOperations jmsOperations;

    public PersonMessenger(JmsOperations jmsOperations) {
        this.jmsOperations = jmsOperations;
    }

    public void sendPersion(final Person person) {
        this.jmsOperations.convertAndSend(person);
    }

    public Person receivePersion() {
        return (Person) this.jmsOperations.receiveAndConvert();
    }
}

@Configuration
@Import({CommonConfiguration.class})
public class MessagingConfiguration {

    public static final String PERSON_QUEUE = "person.queue";

    @Autowired
    private ApplicationEnvironment applicationEnvironment;

    @Bean
    public ConnectionFactory jmsConnectionFactory() {
        final ActiveMQConnectionFactory activeMqConnectionFactory = new ActiveMQConnectionFactory(
                this.applicationEnvironment.getJmsBrokerUrl());
        activeMqConnectionFactory.setTrustAllPackages(true);
        return activeMqConnectionFactory;
    }

    @Bean
    public JmsOperations jmsTemplate(ConnectionFactory connectionFactory) {
        final JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
        jmsTemplate.setDefaultDestinationName(PERSON_QUEUE);
        return jmsTemplate;
    }

    @Bean
    public PersonMessenger personMessenger(JmsOperations jmsOperations) {
        return new PersonMessenger(jmsOperations);
    }

    @Bean(name = PERSON_QUEUE)
    public Queue personQueue() {
        return new ActiveMQQueue(PERSON_QUEUE);
    }
}

@Configuration
@PropertySource("classpath:application.properties")
public class CommonConfiguration {

    @Autowired
    private Environment applicationEnvironment;

    @Bean
    public ApplicationEnvironment applicationEnvironment() {
        return new ApplicationEnvironment(this.applicationEnvironment);
    }
}

application.properties:

jms.brokerUrl=vm://test?async=false&broker.persistent=false&broker.useJmx=false

请注意,测试在尝试从队列中读取 Person 对象时阻塞:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.opessoftware.example.spring.messenger.PersonMessengerTest
2017-02-15 15:30:33,736|WARN|main|o.a.activemq.broker.BrokerService|49670|
    org.apache.activemq.broker.BrokerService.checkMemorySystemUsageLimits(BrokerService.java:2142)
    Memory Usage for the Broker (1024mb) is more than the maximum available for the JVM: 955 mb - resetting to 70% of maximum available: 668 mb
2017-02-15 15:30:33,993|WARN|main|o.a.activemq.broker.BrokerService|49927|
    org.apache.activemq.broker.BrokerService.checkMemorySystemUsageLimits(BrokerService.java:2142)
    Memory Usage for the Broker (1024mb) is more than the maximum available for the JVM: 955 mb - resetting to 70% of maximum available: 668 mb

receiveAndConvert() 调用可能正在创建第二个嵌入式代理,还是可能正在从不同的队列中读取?

使用嵌入式代理进行测试时的一个臭名昭著的问题。

操作之间的连接关闭,没有持久性,数据丢失。

尝试将连接工厂包装在 CachingConnectionFactory 中,以便连接保持打开状态(因此代理保持打开状态)。

出于性能原因,您确实应该将 CachingConnectionFactoryJmsTemplate 一起使用,但在单元测试中它特别糟糕。

Gary Russell , in order to prevent each JMS operation from closing the connection and discarding the embedded broker along with the Person message in the queue, method jmsConnectionFactory() in configuration class MessagingConfiguration now wraps the ActiveMQConnectionFactory (which implements ConnectionFactory) in a CachingConnectionFactory:

@Configuration
@Import({CommonConfiguration.class})
@EnableJms
public class MessagingConfiguration {

    public static final String PERSON_QUEUE = "person.queue";

    @Autowired
    private ApplicationEnvironment applicationEnvironment;

    @Bean
    public ConnectionFactory jmsConnectionFactory() {
        final ActiveMQConnectionFactory activeMqConnectionFactory = new ActiveMQConnectionFactory(
                this.applicationEnvironment.getJmsBrokerUrl());
        activeMqConnectionFactory.setTrustAllPackages(true);
        return new CachingConnectionFactory(activeMqConnectionFactory);
    }

    @Bean
    public JmsOperations jmsTemplate(ConnectionFactory connectionFactory) {
        final JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
        jmsTemplate.setDefaultDestinationName(PERSON_QUEUE);
        return jmsTemplate;
    }

    @Bean
    public PersonMessenger personMessenger(JmsOperations jmsOperations) {
        return new PersonMessenger(jmsOperations);
    }

    @Bean(name = PERSON_QUEUE)
    public Queue personQueue() {
        return new ActiveMQQueue(PERSON_QUEUE);
    }
}

请注意下面的测试通过并仅输出一个 BrokerService 内存警告,这意味着该测试仅创建一个所有 JMS 操作都使用的嵌入式代理。

------------------------------------------------------------------------
Building spring-hibernate-jpa 1.0.0-SNAPSHOT
------------------------------------------------------------------------

--- maven-surefire-plugin:2.10:test (default-cli) @ spring-hibernate-jpa ---
Surefire report directory: /home/derek/Projects/spring-hibernate-jpa/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.opessoftware.example.spring.messenger.PersonMessengerTest
2017-02-16 10:14:03,743|WARN|main|o.a.activemq.broker.BrokerService|1579|
    org.apache.activemq.broker.BrokerService.checkMemorySystemUsageLimits(BrokerService.java:2142)
    Memory Usage for the Broker (1024mb) is more than the maximum available for the JVM: 955 mb - resetting to 70% of maximum available: 668 mb
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.929 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

------------------------------------------------------------------------
BUILD SUCCESS
------------------------------------------------------------------------
Total time: 4.190s
Finished at: Thu Feb 16 10:14:04 EST 2017
Final Memory: 8M/60M
------------------------------------------------------------------------