The Spring Framework provides a JMS abstraction called JmsTemplate. Unfortunately this class acts against a JMS provider in the same way as it acts against JMS in an application server. For example, to send a message, a new connection, session, and producer is created, the message is sent and everything is closed. This is done for every single message.
This behavior is necessary in a managed EJB (J2EE) environment, however, a J2EE application server pools its resources under the covers but if JmsTemplate is used against a plain JMS provider, it turns inefficient and slow.
Spring itself provides a class called SingleConnectionFactory which uses a single shared JMS connection but this does not avoid the creation of sessions, producers and consumers.
SwiftMQ provides an additional library called "springsupport.jar" which is included in SwiftMQ releases 7.3.0 and up. The library uses a shared JMS connection and pools JMS sessions, producer and consumer objects.
To use it with Spring, add it to your client's classpath and use class "com.swiftmq.jms.springsupport.SingleSharedConnectionFactory" as your connection factory as shown in this example:
<bean id="jmsConnectionFactory"
class="org.springframework.jndi.JndiObjectFactoryBean"
lazy-init="true">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="jndiName">
<value>plainsocket@router1</value>
</property>
</bean>
<bean id="testqueue"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="jndiName">
<value>testqueue@router1</value>
</property>
</bean>
<bean id ="singleSharedConnectionFactory"
class="com.swiftmq.jms.springsupport.SingleSharedConnectionFactory"
destroy-method="destroy" >
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
<property name="poolExpiration" value="120000"/>
<property name="clientId" value="test"/>
</bean>
<bean id="jmsTemplate"
class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref bean="singleSharedConnectionFactory"/>
</property>
<property name="defaultDestination">
<ref bean="testqueue"/>
</property>
</bean>
<bean id="springSender"
class="SpringSender">
<property name="jmsTemplate">
<ref bean="jmsTemplate"/>
</property>
</bean>
SingleSharedConnectionFactory uses a single shared JMS connection. This single connection provides pooling for JMS sessions where each JMS session pools producers and consumers.
The class provides 3 properties. One is "targetConnectionFactory" which needs to be set to a "real" connection factory obtained from SwiftMQ's JNDI. It is used to create the single shared JMS connection. The next is "poolExpiration" which defines the time in milliseconds after which a pooled object (session, producer, consumer) will expire when it has not being used within this time. So the pools grow and shrink dependent on the load. Default for "poolExpiration" is 60000 ms (1 minute). The last is "clientId" which is optional and can be set to the JMS client id.
To free all resources held from SingleSharedConnectionFactory define the destroy-method:
<bean id ="singleSharedConnectionFactory"
class="com.swiftmq.jms.springsupport.SingleSharedConnectionFactory"
destroy-method="destroy" >
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
<property name="poolExpiration" value="120000"/>
<property name="clientId" value="test"/>
</bean>
SingleSharedConnectionFactory can also be used from plain JMS clients (without Spring). Just wrap your connection factory with SingleSharedConnectionFactory and you have pooling:
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.swiftmq.jndi.InitialContextFactoryImpl");
env.put(Context.PROVIDER_URL,smqpURL);
InitialContext ctx = new InitialContext(env);
QueueConnectionFactory connectionFactory = new SingleSharedConnectionFactory((QueueConnectionFactory)ctx.lookup(qcfName));
SingleSharedConnectionFactory implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory and can be used for all JMS messaging domains.
To free all resources held from SingleSharedConnectionFactory call destroy:
((SingleSharedConnectionFactory)connectionFactory).destroy();
Debugging of the library can be enabled by setting the System Property "swiftmq.springsupport.debug" to true:
-Dswiftmq.springsupport.debug=true
Debug output goes to System.out.