Closing Session when using Spring's CachingConnectionFactory
Asked Answered
S

2

10

The java doc here related to Spring CachingConnectionFactory has comment :

NOTE: This ConnectionFactory requires explicit closing of all Sessions obtained from its shared Connection. This is the usual recommendation for native JMS access code anyway. However, with this ConnectionFactory, its use is mandatory in order to actually allow for Session reuse.

I am not clear how to handle this with the below given configuration in my application.

<bean id="springApp" class="com.codereq.springcore.jms.SpringJMSListenerApp"  />

<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="jmsConnectionFactory"/>
    <property name="destination" ref="destination"/>
    <property name="messageListener" ref="messageListener"/>
    <property name="sessionTransacted" value="true"/>
    <property name="concurrentConsumers" value="5" />
    <property name="maxConcurrentConsumers" value="15" />
</bean>

<bean id="messageListener" class="com.codereq.springcore.jms.MessageListenerApp" />

<bean id="jmsConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory"
        p:targetConnectionFactory-ref="emsConnectionFactory"
        p:sessionCacheSize="100" 
        p:cacheConsumers="true" />

<bean id="emsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="GenericConnectionFactory"/>
    <property name="jndiTemplate" ref="jndiTemplate"/>
</bean>


<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
        <props>
            <prop key="java.naming.factory.initial">com.tibco.tibjms.naming.TibjmsInitialContextFactory</prop>
            <prop key="java.naming.provider.url">tibjmsnaming://localhost:7222</prop>
            <prop key="java.naming.security.principal">admin</prop>
            <prop key="java.naming.security.credentials">admin</prop>
        </props>
    </property>
</bean>

<bean id="destination" class="com.tibco.tibjms.TibjmsQueue">
    <constructor-arg value="com.sample.queue" />
</bean>

The listener class is this :

public class MessageListenerApp implements MessageListener {

private static int c = 0;

@Override
public void onMessage(Message arg0) {

    try {
        System.out.println("Received Message..."+arg0.getStringProperty("MessageNum")+". Waiting to finish..");
        Thread.sleep(2000);
        System.out.println("Finished processing.."+arg0.getStringProperty("MessageNum")+".."+(c++));
    } catch (Exception e) {
        e.printStackTrace();
    }

}

}

How do I follow recommendation that Sessions obtained from shared connection should be closed explicitly ?

Came across SessionAwareMessageListener interface which provides onMessage method which gives handle to Session. So to properly implement session closing, should this interface be implemented ?

Skyros answered 18/9, 2013 at 2:47 Comment(0)
L
6

It is generally not a good idea to use a caching connection factory with a listener container, especially when using maxConcurrentConsumers > concurrentConsumers - you can end up with cached consumers in the cache, which get messages where there is no listener, and such messages can get "stuck".

So, don't use a CCF in this case, it's really intended for use on the producer side.

Since the container manages concurrency, the sessions/consumers are long-lived and don't need to be cached.

Lundgren answered 18/9, 2013 at 3:38 Comment(10)
But still the question seems unanswered. Let the message producer is cached in another scenario. How to handle the explicit closing of the sessions obtained from CCF ?Evesham
session.close() - the javadoc comment is simply saying that the session is only returned to the pool when the client closes it. If you need a PHYSICAL close, then don't use a CachingConnectionFactory. Spring clients (JmsTemplate, listener container) do close the connection when appropriate.Lundgren
I have configured a CachingConnectionFactory for JMSTemplate to use with Tibco EMS. My message producer is running in a tomcat server. Even after the tomcat is gracefully shutdown, the connection is still not destroyed in EMS. Is there a workaround to close it?Evesham
The connection factory implements DisposableBean which means its destroy() method will be called (closing the connection) when the application context is destroyed. If it's a normal web application context, that should happen automatically; if you are managing the context's lifecycle yourself, it's up to you to destroy it.Lundgren
Its a normal web application context. context's lifecycle is managed by Spring only. in the blog Using Spring to Send JMS messages I could see that adding the daemon=true option to the transport will terminate the connection. But its not woking in my case.Evesham
I suggest you turn on DEBUG logging for org.springframework - it emits copious logging about the bean lifecycle. You should then be able to determine what's preventing the factory from being destroyed.Lundgren
@GaryRussell: So do you suggest that for Spring's DefaultMessageListenerContainer and SimpleMessageListenerContainer one should always use SingleConnectionFactory?Grateful
It depends on what you are doing downstream on the container thread - if you are executing JmsTemplate sends to the same broker using the same factory, you will likely want to cache producers for performance. The only hard and fast rule is you must never cache consumers if you are using variable concurrency in the container.Lundgren
@GaryRussell should be improved the current javadoc for the CachingConnectionFactory class? with the current note in the javadoc gives the impression or seems that something manually should be configured. I did realize that use the Bean's destroyMethod is not valid since CachingConnectionFactory class has no a close methodFitting
@ManuelJordan I am not sure what you mean - let's take it off-line - Stack overflow moderators don't like extended commentary on answers.Lundgren
S
0

Application is not required to close the Session when using DefaultMessageListenerContainer, it creates the required sessions and closes them during shutdown.

Per my understanding the note you mentioned applies when Session is created by application using CachingConnectionFactory reference about which spring will have no clue.

Strage answered 28/4, 2016 at 2:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.