带有JMS主题的ActiveMQ - 一些消息未出列的消息

时间:2014-01-12 10:14:07

标签: activemq spring-jms atomikos jms-topic

我们正在尝试使用JMS主题将ActiveMQ 5.9.0设置为消息代理,但我们在使用消息时遇到了一些问题。

出于测试目的,我们有1个主题,1个事件生成器和1个使用者的简单配置。我们一个接一个地发送10条消息,但每次运行应用程序时,都不会消耗1-3条消息!其他消息被消耗并且处理得很好。 我们可以看到我们在ActiveMQ管理控制台中发布到主题的所有消息,但它们从未到达消费者,即使我们重新申请该应用程序(我们可以看到“入队”和“出队”列中的数字是不同的。)

编辑:我还应该提到,当使用队列而不是主题时,不会发生此问题。

为什么会这样?它可能与atomikos(交易经理)有关吗?或者配置中还有其他东西?欢迎任何想法/建议。 :)

这是ActiveMQ / JMS弹簧配置:

    <bean id="connectionFactory" class="com.atomikos.jms.AtomikosConnectionFactoryBean"
    init-method="init" destroy-method="close">
    <property name="uniqueResourceName" value="amq" />
    <property name="xaConnectionFactory">
        <bean class="org.apache.activemq.spring.ActiveMQXAConnectionFactory"
            p:brokerURL="${activemq_url}" />
    </property>
    <property name="maxPoolSize" value="10" />
    <property name="localTransactionMode" value="false" />
</bean>

<bean id="cachedConnectionFactory"
    class="org.springframework.jms.connection.CachingConnectionFactory">
    <property name="targetConnectionFactory" ref="connectionFactory" />
</bean>

<!-- A JmsTemplate instance that uses the cached connection and destination -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="cachedConnectionFactory" />
    <property name="sessionTransacted" value="true" />
    <property name="pubSubDomain" value="true"/>
</bean>

<bean id="testTopic" class="org.apache.activemq.command.ActiveMQTopic">
    <constructor-arg value="test.topic" />
</bean>

<!-- The Spring message listener container configuration -->
<jms:listener-container destination-type="topic"
    connection-factory="connectionFactory" transaction-manager="transactionManager"
    acknowledge="transacted" concurrency="1">
    <jms:listener destination="test.topic" ref="testReceiver"
        method="receive" />
</jms:listener-container>

制片人:

@Component("producer")
public class EventProducer {

    @Autowired
    private JmsTemplate jmsTemplate;

    @Transactional
    public void produceEvent(String message) {
        this.jmsTemplate.convertAndSend("test.topic", message);
    }
}

消费者:

@Component("testReceiver")
public class EventListener {

    @Transactional
    public void receive(String message) {
        System.out.println(message);
    }  
}

测试:

    @Autowired
    private EventProducer eventProducer;

    public void testMessages() {

    for (int i = 1; i <= 10; i++) {
        this.eventProducer.produceEvent("message" + i);
    }

1 个答案:

答案 0 :(得分:3)

这就是JMS主题的本质 - 只有当前订阅者默认接收消息。您有一个竞争条件,并在消费者在容器启动后建立其订阅之前发送消息。这是单元/集成测试中常见的错误,其中包含您在同一应用程序中发送和接收的主题。

对于更新版本的Spring,有一个method you can poll to wait until the subscriber is established(从3.1开始,我认为)。或者,您可以在开始发送之前等待一段时间,或者您可以使您的订阅持久。