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
相关产品推荐
相关产品推荐

