如何在 Spring 4 中使用 @JmsListener 作为主题

How to use @JmsListener for topic in Spring 4

我正在使用 Spring 4.3.3,我正在尝试收听目标类型为主题的消息。

我可以在xml中实现:

<jms:listener-container connection-factory="connectionFactory"
                        destination-type="topic"
                        message-converter="jackson2MessageConverter">
    <jms:listener destination="test.topic" ref="jmsTopicMessageListener1" method="receiveMessage"/>
    <jms:listener destination="test.topic" ref="jmsTopicMessageListener2" method="receiveMessage"/>
</jms:listener-container>

但是我想使用@JmsListener。目前它仅适用于这样的队列目标:

@JmsListener(destination = "mailbox", containerFactory = "jmsListenerContainerFactory")
public void receiveMessage(DataObject dataObject) {
    System.out.println("Received <" + dataObject.getName() + ">");
}

如何收听带有此注释@JmsListener 的主题?

提前致谢。

更新:

我已经在配置中试过了:

<bean id="topicJmsListenerContainerFactory"
      class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
    <property name="connectionFactory" ref="cachingConnectionFactory"/>
    <property name="destinationResolver" ref="jmsDestResolver"/>
    <property name="concurrency" value="3-10"/>
    <property name="messageConverter" ref="jackson2MessageConverter"/>
    <property name="pubSubDomain" value="true"/>
</bean>

然后这个:

@JmsListener(destination = "test.topic", containerFactory = "topicJmsListenerContainerFactory")
public void receiveMessage(DataObject dataObject) {
    System.out.println("Received <" + dataObject.getName() + ">" + 1);
}

我现在可以获取值,但我得到了重复项。

既然你已经修复了你的配置(你正在接收消息),那么唯一需要解决的问题就是你正在接收重复的消息。这是由于您的这部分配置:

<property name="concurrency" value="3-10"/>

如果您检查 DefaultMessageListenerContainer(JmsListenerContainerFactory 扩展)的 javadoc,您会发现:

...for a topic, you will typically stick with the default number of 1 consumer, otherwise you'd receive the same message multiple times on the same node.

这是由于主题本身的架构,多个消费者将被视为多个订阅者,他们需要接收每条已发送的消息

在解决方案方面:

您可能需要稍微构建一下您的代码。但大多数情况下,从 Topic 更改为 VirtualTopic 都可以完成这项工作。 借助 VirtualTopics,您可以在消费者方面获得 "Queue-like" 行为,这意味着消息将被消费者消费,因此多个消费者无法看到同一条消息两次。

当然,另一种选择是将并行处理工作负载转移到其他地方,在 JMS 入口点使用单个使用者。根据手头的任务,它也可能是一个足够的解决方案。