如何使用 Spring JMS 发布 JMS 主题?

Posted

技术标签:

【中文标题】如何使用 Spring JMS 发布 JMS 主题?【英文标题】:How do you publish a JMS topic with Spring JMS? 【发布时间】:2011-03-31 21:41:37 【问题描述】:

我有一个组件将消息发送到队列以由另一个系统处理。它还应该每隔一段时间发布一个关于工作状态的主题。我可以只使用用于发送到队列和发布到主题的相同 JmsTemplate 吗?

我在 ActiveMQ 中创建了一个新主题,除了当我从 JmsTemplate 发送消息时,使用发送的消息创建一个具有主题名称的新队列(而不是将数据发送到实际主题),我在做什么错了吗?

这是我的配置:

<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
    <constructor-arg ref="amqConnectionFactory" />
    <property name="exceptionListener" ref="jmsExceptionListener" />
    <property name="sessionCacheSize" value="100" />
</bean>

<!--  JmsTemplate Definition -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <constructor-arg ref="connectionFactory" />
</bean>


<bean id="messageFacade" class="org.foo.MessageFacadeJms">
    <property name="jmsTemplate" ref="jmsTemplate" />
</bean>

MessageFacadeJms 是我用来发送队列消息的类(它有效),我也可以用它来发布主题吗?

我可以用它来做队列发送和主题发布吗?:

jmsTemplate.convertAndSend("TOPIC_NAME" /* or queue name */, message);

【问题讨论】:

【参考方案1】:

如果您可以使用队列/主题的命名约定,那么您可以实现自定义org.springframework.jms.support.destination.DestinationResolver

public class NamingDestinationResolver implements DestinationResolver 
   public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain) throws JMSException 
      if (destinationName.endsWith("Queue")) 
         return session.createQueue(destinationName);
       else if (destinationName.endsWith("Topic")) 
         return session.createTopic(destinationName);
      
      throw new RuntimeException("Naming convention not respected for destination " + destinationName);
   

并使用JmsTemplate.setDestinationResolver引用它

【讨论】:

非常适合我。如果你在 DestinationResolver 中添加@Component,你甚至不需要在 JmsTemplate 上设置它 @danielnovy 如果您发现答案有用,我们将不胜感激:)【参考方案2】:

如果您将目标创建为 Spring bean,而不是在代码中使用目标名称,则 Spring 不需要知道它是主题还是队列。否则上面建议的解决方案也应该有效。

可以通过直接实例化它们来创建 AMQ JMS 目标:

  <bean id="destination" class="org.apache.activemq.command.ActiveMQTopic">
    <constructor-arg value="TOPIC_NAME" />
  </bean>

或从 JNDI 获取:

<bean id="topic" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="TOPIC_NAME"/>
        <property name="jndiTemplate" ref="jmsJndiTemplate"/> 
</bean>

我更喜欢 JNDI 技术,因为它更标准。

【讨论】:

【参考方案3】:

这可能看起来有点奇怪,您需要通过将其pubSubDomain 属性设置为true 来告诉 JmsTemplate 这是一个主题而不是队列。

这意味着您将需要两个 JmsTemplate bean,一个用于队列,一个用于主题:

<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
   <constructor-arg ref="connectionFactory" />
   <property name="pubSubDomain" value="false"/>
</bean>

<bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
   <constructor-arg ref="connectionFactory" />
   <property name="pubSubDomain" value="true"/>
</bean>

【讨论】:

以上是关于如何使用 Spring JMS 发布 JMS 主题?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用spring boot jms收听话题

Spring Integration JMS 创建 ActiveMQ 队列而不是主题

如何使用 spring 集成 dsl 从 JMS 队列中解组 XML

如何使用 Spring JMS 在 ActiveMQ 中创建多个侦听器

如何检测 JMS 主题连接丢失

spring整合JMS