Spring and OpenJMS (JMS 1.0.2)

I had a difficult time getting a Spring JmsTemplate configured and connected to my OpenJMS server. There wasn't any complete examples in the Spring documentation. Eventually I did get it working, and I am posting the results here in the hopes that someone else will find it useful.

This configuration fetches the OpenJMS QueueConnectionFactory from JNDI, and sets up a Spring JMS JNDI Destination Resolver to pull named destinations (queues or topics) out of JNDI.

Pass the jmsQueueTemplate or jmsTopicTemplate beans into your own objects as a property, you can use them to send and receive from any OpenJMS queue or topic.

Spring JmsTemplate Warning

Do not use Spring's JMS Template to read messages from a topic (queues are OK), you will lose messages:

Another gotcha I've seen folks do is to create a MessageConsumer inside one of the SessionCallback methods then wonder why messages are not being received. After the SessionCallback is called, the session will be closed; which will close your consumers too . So if you want to create a MessageConsumer you should create a connection, session and consumer yourself. (BTW it might be nice to make the createConsumer & createSession methods public on JmsTemplate).

(quoted from ActiveMQ's JmsTemplate Gotchas Page)

Application Context XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//Spring//DTD Bean//EN" 
    "http://www.springframework.org/dtd/spring-beans.dtd">

<!-- Application Context -->
<beans>
    <!-- Property Placeholder Post-Processor (Handles ${variables}) -->
    <bean id="placeholderConfig"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location"><value>classpath:/bootstrap.properties</value></property>
    </bean>

    <!-- JNDI Environment Template -->
    <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">${jms.jndiContextFactory}</prop>
                <prop key="java.naming.provider.url">${jms.jndiProviderUrl}</prop>
            </props>
        </property>
    </bean>

    <!-- Internal JMS Queue Connection Factory -->
    <bean id="internalJmsQueueConnectionFactory"
        class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate">
            <ref bean="jndiTemplate"/>
        </property>
        <property name="jndiName">
            <value>${jms.queueConnectionFactoryName}</value>
        </property>
    </bean>

    <!-- Spring Wrapped JMS Queue Connection Factory -->
    <bean id="jmsQueueConnectionFactory"
        class="org.springframework.jms.connection.SingleConnectionFactory102">
        <property name="targetConnectionFactory">
            <ref bean="internalJmsQueueConnectionFactory"/>
        </property>
        <property name="pubSubDomain">
            <value>false</value>
        </property>
    </bean>

    <!-- Internal JMS Topic Connection Factory -->
    <bean id="internalJmsTopicConnectionFactory"
        class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate">
            <ref bean="jndiTemplate"/>
        </property>
        <property name="jndiName">
            <value>${jms.topicConnectionFactoryName}</value>
        </property>
    </bean>

    <!-- Spring Wrapped JMS Queue Connection Factory -->
    <bean id="jmsTopicConnectionFactory"
        class="org.springframework.jms.connection.SingleConnectionFactory102">
        <property name="targetConnectionFactory">
            <ref bean="internalJmsTopicConnectionFactory"/>
        </property>
        <property name="pubSubDomain">
            <value>true</value>
        </property>
    </bean>

    <!-- JMS Destination Resolver -->
    <bean id="jmsDestinationResolver"
        class="org.springframework.jms.support.destination.JndiDestinationResolver">
        <property name="jndiTemplate">
            <ref bean="jndiTemplate"/>
        </property>
        <property name="cache">
            <value>true</value>
        </property>
    </bean>

    <!-- JMS Queue Template -->
    <bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate102">
        <property name="connectionFactory">
            <ref bean="jmsQueueConnectionFactory"/>
        </property>
        <property name="destinationResolver">
            <ref bean="jmsDestinationResolver"/>
        </property>
        <property name="pubSubDomain">
            <value>false</value>
        </property>
        <property name="receiveTimeout">
            <value>2000</value>
        </property>
    </bean>

    <!-- JMS Topic Template -->
    <bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate102">
        <property name="connectionFactory">
            <ref bean="jmsTopicConnectionFactory"/>
        </property>
        <property name="destinationResolver">
            <ref bean="jmsDestinationResolver"/>
        </property>
        <property name="pubSubDomain">
            <value>true</value>
        </property>
    </bean>
</beans>