Tuning Spring JMS Support

We have developed a Spring application that is supposed to run in a Weblogic 8.x environment. Additionally, we used the JMS support that Spring provides. We really liked it for the simplicity of setting up the Message-Driven POJOs.
We did everything as described in the manual ( http://static.springframework.org/spring/docs/2.0.x/reference/jms.html ). The manual is sufficient to setup a successful message sender and a queue listener, therefore I’m not going the get into the details of starting the project.

The Problem

After we delivered the project the client comes back to us and says that during the testing they observed the number of connections made to the weblogic JMS server is increasing more that usually. The application was running as expected and no memory leaks have been found. But they couldn’t figure out why the number of connections was increasing even where the server was not receiving any requests from outside. So we have taken a look at weblogic console page in question: <DomainName>->Servers-><ServerName>->Monitoring Tab->JMS sub-Tab.
Here, by refreshing the page, we were able to see that the “Total Connections” was increasing constantly even without having any messages sent to the queue. We realized that this behavior can only be generated by the Listener that constantly polls the JMS queue to see if there are new messages waiting.

So we went back to the spring configuration file and analyzed the snippet that is responsible for listening to the JMS queue:

<bean id="MessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer102" >
	<property name="maxConcurrentConsumers" value="5"/>
	<property name="connectionFactory" ref="queueConnectionFactory" />
	<property name="destination" ref="SendCountQueue" />
	<property name="messageListener" ref="SendCountMessageListener" />
	<property name="transactionManager" ref="jtaTransactionManager" />
</bean>

With these settings we can only control the number of concurrent connections we make to the JMS server by using the maxConcurrentConsumers parameter. But we had no control over how often we make these connections.

The Solution

Since the Listener needs to poll the queue on a constant basis, we need a way to cache the connections and reuse them for the next poll.
At that time, we Googled for a way to tune this kind of behavior and had no success (I guess is too obvious on how to do it). Didn’t spend much time on this side ’cause we realized that we are in the beautiful world of Spring where everything is a bean with getters and setters. The setters are used when configuring the bean in the XML file through the property tags.
So we opened the Spring API for DefaultMessageListenerContainer http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/jms/listener/DefaultMessageListenerContainer.html and found a method called setCacheLevelName(String constantName). Bingo!
All we have to do is set the cache level from the following options: CACHE_CONNECTION, CACHE_CONSUMER, CACHE_NONE, CACHE_SESSION. Well, but these are more options that we actually thought about. After scratching our heads we decided to go with CACHE_SESSION. This will not only cache the connection but the session, too.

Then we added this new parameter to our bean definition: <property name=”cacheLevelName” value=”CACHE_SESSION”/>
So we ended up having the following final bean definition:

<bean id="MessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer102" >
	<property name="maxConcurrentConsumers" value="5"/>
	<property name="connectionFactory" ref="queueConnectionFactory" />
	<property name="destination" ref="SendCountQueue" />
	<property name="messageListener" ref="SendCountMessageListener" />
	<property name="transactionManager" ref="jtaTransactionManager" />
	<property name="cacheLevelName" value="CACHE_SESSION"/>
</bean>

Problem solved! 🙂

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply