使用Spring的CachingConnectionFactory时如何关闭会话

10

Spring CachingConnectionFactory的Java文档在这里有注释:

注意:此连接工厂需要显式关闭从其共享连接获取的所有会话。这通常是针对本机JMS访问代码的建议。然而,对于此ConnectionFactory,它的使用是强制性的,以实际允许会话重用。

我不清楚如何处理下面给出的应用程序配置。

<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>

监听器类是这样的:

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();
    }

}

}

我应该如何遵循“从共享连接获取的会话应该明确关闭”的建议?

我发现了SessionAwareMessageListener接口,它提供了onMessage方法,可以操作Session。因此,要正确实现Session的关闭,是否应该实现该接口?

2个回答

6

通常不建议在使用监听器容器时使用缓存连接工厂,特别是当使用 maxConcurrentConsumers > concurrentConsumers 时 - 您可能会在缓存中得到已缓存的消费者,在没有监听器的情况下接收消息,这些消息可能会被“卡住”。

因此,在这种情况下不要使用 CCF,它真正意义上是为生产者端使用而设计的。

由于容器管理并发性,因此会话/消费者是长期存在的,并且不需要被缓存。


但是问题似乎仍未得到解答。假设消息生产者在另一种情况下被缓存,如何处理从CCF获取的会话的显式关闭? - Manu
session.close() - javadoc注释只是说明当客户端关闭会话时,会话才会返回到池中。如果您需要物理关闭,则不要使用CachingConnectionFactory。Spring客户端(JmsTemplate、监听器容器)在适当的时候会关闭连接。 - Gary Russell
我已经为JMSTemplate配置了一个CachingConnectionFactory,用于与Tibco EMS一起使用。我的消息生产者正在Tomcat服务器上运行。即使Tomcat已经优雅地关闭,连接在EMS中仍然没有被销毁。是否有解决方法来关闭它? - Manu
连接工厂实现了 DisposableBean 接口,这意味着当应用程序上下文被销毁时会调用它的 destroy() 方法(关闭连接)。如果它是一个普通的 Web 应用程序上下文,那么这应该会自动发生;如果您正在自己管理上下文的生命周期,则需要您自行销毁它。 - Gary Russell
这是一个普通的Web应用程序上下文。上下文的生命周期仅由Spring管理。在博客使用Spring发送JMS消息中,我发现将daemon=true选项添加到传输中将终止连接。但在我的情况下它不起作用。 - Manu
显示剩余5条评论

0

在使用DefaultMessageListenerContainer时,无需关闭会话(Session),它会在关闭期间创建所需的会话并将其关闭。

根据我的理解,您提到的注释适用于应用程序使用CachingConnectionFactory引用创建会话时,Spring不知道该引用的情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接