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

Spring Boot集成IBM MQ遇JMSCC0111错误:Client ID重复问题求助

问题

使用Spring Boot 3.3.4集成IBM MQ,已在配置文件中指定唯一的订阅者client-id,但JMS健康检查失败,报错如下:

2024-10-28T15:47:30.173-04:00  WARN 14156 --- [(2)-10.1.81.174] o.s.boot.actuate.jms.JmsHealthIndicator  : JMS health check failed
com.ibm.msg.client.jakarta.jms.DetailedInvalidClientIDException: JMSCC0111: IBM MQ classes for JMS attempted to set a pre-existing client ID on a Connection or JMSContext.
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[na:na]
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[na:na]
    at com.ibm.msg.client.commonservices.j2se.NLSServices.createException(NLSServices.java:334) ~[com.ibm.mq.jakarta.client-9.3.3.0.jar:9.3.3.0 - p933-L230531]
    at com.ibm.msg.client.commonservices.nls.NLSServices.createException(NLSServices.java:226) ~[com.ibm.mq.jakarta.client-9.3.3.0.jar:9.3.3.0 - p933-L230531]
    at com.ibm.msg.client.jakarta.jms.internal.JmsErrorUtils.createException(JmsErrorUtils.java:126) ~[com.ibm.mq.jakarta.client-9.3.3.0.jar:9.3.3.0 - p933-L230531]

配置文件(application.properties)

ibm.mq.queue-manager=${MQ_QUEUE_MANAGER}
ibm.mq.topicName=${MQ_TOPIC_NAME}
ibm.mq.channel=${MQ_CHANNEL}
ibm.mq.connName=${MQ_HOSTNAME}
ibm.mq.user=${MQ_USERNAME}
ibm.mq.password=${MQ_PASSWORD}
ibm.mq.application-name=${MQ_SUBSCRIBER_NAME}
ibm.mq.client-id=${MQ_SUBSCRIBER_CLIENT_ID}

MQ连接配置类

import com.ibm.mq.jakarta.jms.MQConnectionFactory;
import com.ibm.mq.spring.boot.MQConfigurationProperties;
import com.ibm.mq.spring.boot.MQConnectionFactoryCustomizer;
import com.ibm.mq.spring.boot.MQConnectionFactoryFactory;
import jakarta.jms.ConnectionFactory;
import java.util.List;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;

@Configuration
@EnableJms
public class MQConnectionConfiguration {

    @Bean
    @ConfigurationProperties("ibm.mq")
    public MQConfigurationProperties ibmProductConfigProperties() {
        return new MQConfigurationProperties();
    }

    @Bean
    public MQConnectionFactory connectionFactory(final MQConfigurationProperties properties,
                                                         ObjectProvider<List<MQConnectionFactoryCustomizer>> factoryCustomizers) {
        return new MQConnectionFactoryFactory(properties, factoryCustomizers.getIfAvailable()).createConnectionFactory(MQConnectionFactory.class);
    }

    @Bean
    public JmsListenerContainerFactory<?> jmsListenerContainerFactory(@Qualifier("connectionFactory") ConnectionFactory connectionFactory,
                                                                              DefaultJmsListenerContainerFactoryConfigurer configurer) {
        final DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setSubscriptionDurable(true);
        configurer.configure(factory, connectionFactory);
        return factory;
    }
}

Gradle依赖

implementation("org.springframework.integration:spring-integration-jms:4.3.2.RELEASE")
implementation("javax.jms:javax.jms-api:2.0.1")
implementation 'com.ibm.mq:mq-jms-spring-boot-starter:3.1.2'

解决方案

1. 为健康检查单独配置无client-id的ConnectionFactory

Spring Boot Actuator的JMS健康检查会创建新连接,若使用带固定client-id的ConnectionFactory,会和Listener容器的连接冲突。需单独提供一个未设置client-id的ConnectionFactory供健康检查使用:

修改配置类,新增健康检查专用ConnectionFactory:

import org.springframework.beans.BeanUtils;

// ... 原有代码保持不变

@Bean("healthConnectionFactory")
public MQConnectionFactory healthConnectionFactory(final MQConfigurationProperties properties,
                                                   ObjectProvider<List<MQConnectionFactoryCustomizer>> factoryCustomizers) {
    // 复制原有配置并清除client-id
    MQConfigurationProperties healthProps = new MQConfigurationProperties();
    BeanUtils.copyProperties(properties, healthProps);
    healthProps.setClientId(null);
    
    return new MQConnectionFactoryFactory(healthProps, factoryCustomizers.getIfAvailable()).createConnectionFactory(MQConnectionFactory.class);
}

在application.properties中指定健康检查使用该ConnectionFactory:

management.health.jms.connection-factory-bean-name=healthConnectionFactory

2. 修复依赖版本冲突

Spring Boot 3.3.4基于Jakarta EE 9+,原有依赖存在版本不兼容问题:

  • 移除javax.jms:javax.jms-api,替换为Jakarta版本
  • 升级spring-integration-jms至与Spring Boot 3.3.x匹配的版本(对应Spring Integration 6.2.x)

更新后的Gradle依赖:

implementation("jakarta.jms:jakarta.jms-api:3.1.0")
implementation("org.springframework.integration:spring-integration-jms:6.2.4")
implementation 'com.ibm.mq:mq-jms-spring-boot-starter:3.1.2'

3. 调整client-id的设置层级

将client-id从ConnectionFactory层面移至Listener容器层面,避免全局冲突:

修改JmsListenerContainerFactory配置:

@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerFactory(@Qualifier("connectionFactory") ConnectionFactory connectionFactory,
                                                                 DefaultJmsListenerContainerFactoryConfigurer configurer) {
    final DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setSubscriptionDurable(true);
    // 在容器层面设置client-id
    factory.setClientId("${MQ_SUBSCRIBER_CLIENT_ID}");
    configurer.configure(factory, connectionFactory);
    return factory;
}

同时删除application.properties中的ibm.mq.client-id配置,避免ConnectionFactory自动设置client-id。

4. 检查MQ服务器的client-id占用

即使本地配置唯一,也需确认MQ服务器上是否存在相同client-id的活跃连接。可通过runmqsc命令查询:

DISPLAY CONN(*) WHERE(CLIENTID EQ '你的client-id')

若存在活跃连接,先手动断开,再重启应用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 16:40:59