Spring MQ JMS reconnect configuration

likeToCode picture likeToCode · Jul 18, 2013 · Viewed 10.3k times · Source

First I have a question on how to configure JMS MQ to reconnect to an application when the broker connection is shutdown and restarted.

Below is what I tried,

This is the configuration that I initially had in my spring-mq-jms-connections.xml

<!-- Spring JMS Queue Connection Factory -->
        <!--
        <bean id="jmsQueueConnectionFactory.7"
            class="org.springframework.jms.connection.SingleConnectionFactory"  >
            <property name="targetConnectionFactory">
                <ref bean="internalJmsQueueConnectionFactory.7"/>
            </property>
        </bean> -->

I replaced this with the below configuration introduced "DefaultMessageListenerContainer" which would wrap "SingleConnectionFactory".

<bean id="jmsQueueConnectionFactory.7" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory">
            <ref bean="single.connection.factory.7"/>
        </property>

        <property name="recoveryInterval" value="5000"/>

    </bean>

    <bean id="single.connection.factory.7" class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory">
        <ref bean="internalJmsQueueConnectionFactory.7"/>
    </property>
    </bean>

But I started getting the below exception after this configuration change.

Failed to configure emapi:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'senderAgent.7' defined in URL 
[file://localhost/home/qos/qosdata/config/general/emapi/spring-mq-jms-connections.xml]: 
Cannot resolve reference to bean 'jmsQueueTemplate.7' while setting bean property 'jmsTemplate';
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean 
with name 'jmsQueueTemplate.7' defined in URL 
[file://localhost/home/qos/qosdata/config/general/emapi/spring-mq-jms-connections.xml]: 
Cannot resolve reference to bean 'jmsQueueConnectionFactory.7' while setting bean property 'connectionFactory'; 
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
'jmsQueueConnectionFactory.7' defined in URL [file://localhost/home/qos/qosdata/config/general/emapi/spring-mq-jms-connections.xml]: 
Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 
Property 'destination' or 'destinationName' is required
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:104)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1244)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1008)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:470)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
        at java.security.AccessController.doPrivileged(Native Method)

It says 'destination' or 'destinationName' is required, I am dealing with legacy code, not sure where to look for this or I am doing the right thing when I changed the configuration.

Please suggest if there is any better way to reconnect OpenMQ with an application when the broker connection goes down due to exception or when it is restarted. I also looked at spring jms connection factory with exception listener, but couldnt figure out.

Answer

Gary Russell picture Gary Russell · Jul 18, 2013

A DefaultMessageListenerContainer is a listener container (used to receive messages from the broker), not a connection factory.

If you are just using it as a vehicle to reconnect, it needs a dummy queue to "listen" to.

EDIT: Updated in response to your comment below.

Consider using Spring Integration; it can be configured to automatically fail over; something like

<int:gateway service interface="foo.Bar" default-request-channel="foo" />

<int:channel id="foo">
    <int:dispatcher load-balancer="false"/>
<int:channel/>

<int-jms:outbound-channel-adapter channel="foo" order="1" ... />

<int-file:outbound-channel-adapter channel="foo" order="2" mode="APPEND" ... />

By default, the dispatcher will load balance (round robin) to the two adapters by turning off load balancing it will always send it to JMS and fail over to the file.

Spring Integration also has lots of features for error handling, adding a retry advice to the adapter etc, etc.

If you don't want to use Spring Integration, you can simply do something like...

try {
    this.jmsTemplate.send(...);
}
catch (Exception e) {
    writeToFile(...);
}