升级spring-jms后setExceptionListener方法调用被禁止的问题排查
问题:Spring JMS升级后连接IBM MQ报错
Method setExceptionListener not permitted 我使用@JmsListener消费部署在WAS上的IBM MQ消息,在spring-jms 5.2.22.RELEASE版本时:
- 应用启动时会抛出如下异常:
DEBUG o.s.j.l.DefaultMessageListenerContainer Could not establish shared JMS Connection - leaving it up to asynchronous invokers to establish a Connection as soon as possible javax.jms.IllegalStateException: Method setExceptionListener not permitted at com.ibm.ejs.jms.JMSCMUtils.methodNotPermittedException(JMSCMUtils.java:268) at com.ibm.ejs.jms.JMSConnectionHandle.checkRestrictedMethod(JMSConnectionHandle.java:867) at com.ibm.ejs.jms.JMSConnectionHandle.setExceptionListener(JMSConnectionHandle.java:361) at org.springframework.jms.connection.SingleConnectionFactory.prepareConnection(SingleConnectionFactory.java:458) at org.springframework.jms.connection.SingleConnectionFactory.initConnection(SingleConnectionFactory.java:355) at org.springframework.jms.connection.SingleConnectionFactory.getConnection(SingleConnectionFactory.java:328) at org.springframework.jms.connection.SingleConnectionFactory.createConnection(SingleConnectionFactory.java:243) at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:197) [...]
- 但后续连接能自动恢复,消息可以正常消费:
DEBUG o.s.j.l.DefaultMessageListenerContainer JMS message listener invoker needs to establish shared Connection DEBUG o.s.j.l.DefaultMessageListenerContainer Successfully refreshed JMS Connection
将spring-jms升级到5.3.27后(实际从5.3.26版本开始出现问题),连接无法刷新,持续抛出如下异常,无法消费消息:
ERROR o.s.j.l.DefaultMessageListenerContainer Could not refresh JMS Connection for destination 'XXX' - retrying using FixedBackOff{interval=5000, currentAttempts=0, maxAttempts=unlimited}. Cause: Method setExceptionListener not permitted javax.jms.IllegalStateException: Method setExceptionListener not permitted at com.ibm.ejs.jms.JMSCMUtils.methodNotPermittedException(JMSCMUtils.java:268) at com.ibm.ejs.jms.JMSConnectionHandle.checkRestrictedMethod(JMSConnectionHandle.java:867) at com.ibm.ejs.jms.JMSConnectionHandle.setExceptionListener(JMSConnectionHandle.java:361) at org.springframework.jms.connection.SingleConnectionFactory.prepareConnection(SingleConnectionFactory.java:446) at org.springframework.jms.connection.SingleConnectionFactory.initConnection(SingleConnectionFactory.java:355) at org.springframework.jms.connection.SingleConnectionFactory.getConnection(SingleConnectionFactory.java:328) at org.springframework.jms.connection.SingleConnectionFactory.createConnection(SingleConnectionFactory.java:243) at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:197) [...]
相关代码
业务消费代码
@Transactional @JmsListener(containerFactory = "jmsListenerContainerFactory", destination = "XXX") public void handleMessage(String message){ //... }
MQ配置类
@Configuration @EnableTransactionManagement @EnableJms public class MqConfig{ @Bean public ConnectionFactory mqConnectionFactory() throws NamingException{ return (ConnectionFactory) new JndiObjectFactoryBean().getJndiTemplate().lookup("jms/MqConnFact"); } @Bean public CachingConnectionFactory cachingConnectionFactory() throws NamingException{ CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(); cachingConnectionFactory.setTargetConnectionFactory(mqConnectionFactory()); cachingConnectionFactory.setCacheConsumers(true); cachingConnectionFactory.setCacheProducers(true); cachingConnectionFactory.setSessionCacheSize(10); cachingConnectionFactory.setReconnectOnException(true); return cachingConnectionFactory; } @Bean public JmsListenerContainerFactory jmsListenerContainerFactory() throws NamingException{ DefaultJmsListenerContainerFactory containerFactory = new DefaultJmsListenerContainerFactory(); containerFactory.setConnectionFactory(cachingConnectionFactory()); containerFactory.setConcurrency("1"); containerFactory.setSessionAcknowledgeMode(2); containerFactory.setTransactionManager(jmsTransactionManager()); containerFactory.setCacheLevelName("CACHE_CONSUMER"); containerFactory.setSessionTransacted(true); containerFactory.setReceiveTimeout(60000); return containerFactory; }
我怀疑该问题与Spring Framework 5.3.26版本的某个变更相关,但不清楚具体解决办法,求排查思路。
排查思路
- 绕过
setExceptionListener调用:自定义SingleConnectionFactory子类,重写prepareConnection方法,跳过setExceptionListener的执行逻辑。因为Spring 5.3.26的变更可能强制在连接准备阶段设置该监听器,而WAS的MQ连接不允许此操作。 - 调整CachingConnectionFactory配置:当前设置了
setReconnectOnException(true),结合Spring的变更,可能在连接刷新时重复触发准备逻辑,导致每次都调用受限方法。可以尝试关闭该配置,或者调整缓存策略(比如临时关闭连接缓存作为验证)。 - 使用原生ConnectionFactory:临时去掉
CachingConnectionFactory包装,直接使用从JNDI获取的原生连接工厂,验证是否是缓存层导致的问题(注意这会失去缓存性能优势,仅作为排查手段)。 - 检查WAS MQ连接工厂配置:登录WAS控制台,查看IBM MQ连接工厂是否有禁止调用
setExceptionListener的限制,尝试调整配置解除限制,或者参考IBM官方文档确认该限制的原因。 - 回退版本并跟进官方修复:如果业务紧急,暂时回退到5.3.25版本,同时关注Spring官方是否发布了兼容性修复版本,也可以向Spring社区提交该兼容性问题反馈。
内容的提问来源于stack exchange,提问作者adolzi
相关产品推荐
相关产品推荐

