I have a small Spring MVC webapp (which embeds ActiveMQ) that is designed to run in a local Tomcat, and reliably message to a queue on a remote ActiveMQ.
All of that's in place, except for the "reliably". At the moment, if the remote site goes down, the send fails dramatically. My send config:
<!-- Connection setup -->
<bean id="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="tcp://backend-server-box:61616" />
<bean id="cachedConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory"
p:targetConnectionFactory-ref="connectionFactory"
p:sessionCacheSize="10" />
<!-- Bean that represents the correct destination on the backend server -->
<bean id="backendDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="jmsQueueName" />
</bean>
<bean id="backendTemplate"
class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="cachedConnectionFactory"
p:defaultDestination-ref="backendDestination" />
<!-- Bean that sends to the correct destination on the backend server -->
<bean id="simpleSender" class="uk.co.mycompany.client.messaging.SimpleSender">
<property name="jmsTemplate" ref="backendTemplate" />
</bean>
I think what I need is a local, persistent broker that the connectionFactory (the first bean defined above) points to, which is aware of the remote broker (a JMS to JMS bridge?) If there's a clear bit of documentation to deal with this I'd be very happy to be pointed at it, but I've had to cobble things together, mostly from the extremely helpful BruceBlog. Or any direct help would be great.
Thanks
Update. Some fixes:
Update 2. I've answered it properly, below. Doesn't need any of that amq stuff!
This is how to do it.
You need to declare the following namespaces:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:jms="http://www.springframework.org/schema/jms"
<bean id="bridgedBroker" class="org.apache.activemq.broker.BrokerService"
init-method="start" destroy-method="stop">
<property name="brokerName" value="bridgedBroker"/>
<property name="persistent" value="true"/>
<property name="transportConnectorURIs">
<value>vm://localhost:7001</value>
</property>
<property name="jmsBridgeConnectors">
<bean class="org.apache.activemq.network.jms.JmsQueueConnector">
<property name="outboundQueueConnectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL"
value="failover:(tcp://destination-box:61616)?maxReconnectDelay=10" />
</bean>
</property>
<property name="outboundQueueBridges">
<list>
<bean class="org.apache.activemq.network.jms.OutboundQueueBridge">
<constructor-arg value="queue1"/>
</bean>
<bean class="org.apache.activemq.network.jms.OutboundQueueBridge">
<constructor-arg value="queue2"/>
</bean>
</list>
</property>
</bean>
</property>
</bean>
So you're using persistence, activated by a property, and a Broker Configuration URI to configure retry behaviour. You have to list the name of each remote queue you want to connect to in the outboundBridgeQueues list.
This one connects to the above broker:
<bean id="brokerConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="vm://localhost:7001" />
Then wrap it with a CachingConnectionFactory (almost always a good idea):
<bean id="cachingBrokerConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory"
p:targetConnectionFactory-ref="brokerConnectionFactory"
p:sessionCacheSize="10" />
Each destination you’ll be talking to now needs a local representation:
<bean id="queue1destination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue1" />
</bean>
<bean id="queue2destination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue2" />
</bean>
I’ll just make one for queue1 here; queue2 is exactly the same process:
<bean id="queue1JMSTemplate"
class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="cachingBrokerConnectionFactory"
p:defaultDestination-ref="queue1destination" />
Some sample code:
public class SendToQueue1
{
@Autowired protected JmsTemplate queue1JMSTemplate;
public void sendMessage(final String message) throws JMSException
{
queue1JMSTemplate.send(new MessageCreator()
{
public Message createMessage(Session session) throws JMSException
{
return session.createTextMessage(message);
}
});
}
}
And you're done! Not actually too painful, but it took a while to get it working. Hope this helps people in the future; it's a great way to quickly add persistent messaging to a small app.
Note: this isn't a great way to wire up the class. You'd probably pass in a JMSTemplate from config, so you could use one class definition and wire it into different templates for different queues. I've just done it like this for speed. Just use your Spring instincts :)
Apache's Active MQ website gives an example on how to embed a broker in Spring: http://activemq.apache.org/spring-support.html and on how to define a JMS bridge: http://activemq.apache.org/jms-to-jms-bridge.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With