You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JMS Template确认前关闭连接致会话异常问题排查

问题:JMS消费者确认消息时抛出Session已关闭异常

消费者通过Spring JmsTemplate读取MQ消息后,执行acknowledge()时抛出如下异常:

com.ibm.msg.client.jms.DetailedIllegalStateException: JMSCC0020: This session is closed. An application called a method that must not be used after the session is closed. Ensure that the session is not closed before calling the method.

相关配置与代码

Spring Bean配置

<beans>
    <bean id="mqDestinationResolver"
          class="org.springframework.jms.support.destination.DynamicDestinationResolver">
    </bean>
    <bean id="QUEUE_CONNECTION_FACTORY" class="com.ibm.mq.jms.MQConnectionFactory" >
        <property name="transportType" value="1" />
        <property name="queueManager" value="QM.XXX" />
        <property name="hostName" value="XXX.com" />
        <property name="port" value="XXX" />
        <property name="channel" value="XXX" />
        <property name="SSLCipherSuite" value="XXX" />
    </bean>
    <bean id="destination" class="com.ibm.mq.jms.MQQueue">
        <constructor-arg value="INTERQUEUE" />
    </bean>
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="QUEUE_CONNECTION_FACTORY" />
        <property name="destinationResolver" ref="mqDestinationResolver"/>
        <property name="defaultDestination">
            <ref bean="destination" />
        </property>
        <property name="pubSubDomain" value="false"/>
        <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
    </bean>
    <bean id="messageConsumer" class="com.jms.JmsMessageConsumer">
        <property name="jmsTemplate" ref="jmsTemplate"/>
    </bean>
</beans>

消费者类代码

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.springframework.jms.core.JmsTemplate;

public class JmsMessageConsumer {

private JmsTemplate jmsTemplate;

public JmsTemplate getJmsTemplate() {
    return jmsTemplate;
}

public void setJmsTemplate(JmsTemplate jmsTemplate) {
    this.jmsTemplate = jmsTemplate;
}

public Message receiveMessage() throws JMSException {
    System.out.println("Start  : Inside JMS message Consumer");
    Message msg =(Message)getJmsTemplate().receive();
    msg.acknowledge();
    System.out.println("End  : Inside JMS message Consumer");
    return msg;
}}

原因分析

  • JmsTemplate的receive()方法默认会自动创建Session/Connection,完成操作后立即关闭。当你在receive()之后调用msg.acknowledge()时,该消息所属的Session已经被JmsTemplate销毁,因此触发"Session已关闭"的异常。
  • 虽然配置了CLIENT_ACKNOWLEDGE手动确认模式,但JmsTemplate的默认生命周期管理逻辑导致Session无法在receive()之后保留。

解决方案

方案1:使用JmsTemplate回调方法在Session生命周期内完成确认

通过execute()方法将消息接收和确认逻辑放在同一个Session上下文里,避免Session提前关闭:

public Message receiveMessage() throws JMSException {
    System.out.println("Start  : Inside JMS message Consumer");
    return getJmsTemplate().execute(session -> {
        // 在当前session内创建消费者
        javax.jms.MessageConsumer consumer = session.createConsumer(getJmsTemplate().getDefaultDestination());
        Message msg = consumer.receive();
        if (msg != null) {
            // 此时session仍处于活跃状态,可安全确认
            msg.acknowledge();
        }
        System.out.println("End  : Inside JMS message Consumer");
        return msg;
    }, true); // 让JmsTemplate负责关闭Connection
}

方案2:配置JmsTemplate缓存Session

修改JmsTemplate的缓存级别,让它复用Session而非每次操作都关闭:
在Spring配置的jmsTemplate中添加属性:

<property name="cacheLevelName" value="CACHE_SESSION"/>

注意:缓存的Session并非线程安全,多线程消费场景下需谨慎使用。

方案3:改用消息监听器模式(推荐)

实现MessageListener接口,由Spring统一管理Session生命周期,在onMessage方法内安全执行确认:

  1. 修改消费者类:
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;

public class JmsMessageConsumer implements MessageListener {

    @Override
    public void onMessage(Message msg) {
        System.out.println("Start  : Inside JMS message Consumer");
        try {
            msg.acknowledge();
            System.out.println("End  : Inside JMS message Consumer");
        } catch (JMSException e) {
            // 按需处理异常
            e.printStackTrace();
        }
    }
}
  1. 添加消息监听容器配置:
<bean id="jmsListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="QUEUE_CONNECTION_FACTORY"/>
    <property name="destination" ref="destination"/>
    <property name="messageListener" ref="messageConsumer"/>
    <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
</bean>

这种方式是Spring JMS消费的标准实现,能有效避免Session生命周期管理问题。


内容的提问来源于stack exchange,提问作者Sarvesh H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 04:55:23