Reputation: 3881
I have a component that sends messages to a queue to be handled by another system. It should also publish a topic about job statuses every once in a while. Can I just use the same JmsTemplate used to send to a queue AND to publish to a topic?
I created a new topic in ActiveMQ, except that when I send from JmsTemplate a message, a new queue with the topic name gets created with the sent message (instead of sending the data to the actual topic), what am I doing wrong here?
here's my config:
<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 is the class I use to send a queue message (and it works), can I also just used that to publish a topic?
Can I just use this to do both queue sending and topic publishing?:
jmsTemplate.convertAndSend("TOPIC_NAME" /* or queue name */, message);
Upvotes: 29
Views: 47399
Reputation: 23169
If it's ok for you to use a naming convention for queue/topics, then you can implement a custom 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);
}
}
and reference it using JmsTemplate.setDestinationResolver
Upvotes: 9
Reputation: 2365
If you create the destination as a spring bean rather than using the destination name in your code, Spring won't need to know whether it is a topic or a queue. Else the solution suggested above should work as well.
AMQ JMS destinations can be created by directly instantiating them:
<bean id="destination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="TOPIC_NAME" />
</bean>
or fetching from JNDI:
<bean id="topic" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="TOPIC_NAME"/>
<property name="jndiTemplate" ref="jmsJndiTemplate"/>
</bean>
I prefer the JNDI technique as it is more standard.
Upvotes: 7
Reputation: 403441
This might seem a bit odd, you need to tell JmsTemplate that it's a topic rather than a queue, by setting its pubSubDomain
property to true
.
That means you're going to need two JmsTemplate
beans, one for the queue, and one for the topic:
<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>
Upvotes: 53