Spring Integration:JMS消息驱动适配器回滚时避免日志污染
问题
我正在使用Spring Integration(Java DSL)消费JMS(MQ和Solace)的消息。部分场景下,流程抛出异常时,我希望消息回滚至传输层并重试。
当前配置如下:
@Bean IntegrationFlow myFlow() { return IntegrationFlows.from(Jms.messageDrivenChannelAdapter(conFactory) .configureListenerContainer(c -> c.sessionTransacted(true)) .destination(myQueue)) .handle(myHandler) .get(); }
当myHandler抛出异常时,消息会按预期回滚并重新投递/处理,但日志中会出现如下WARN日志及异常堆栈:
... WARN ... DefaultMessageListenerContainer : Execution of JMS message listener failed, and no ErrorHandler has been set.
由于部分场景下该行为(检测到特定异常需重新处理消息)是预期的,我希望抑制该异常及WARN日志以避免日志污染。
我尝试添加errorChannel,配置如下:
@Bean IntegrationFlow myFlow() { return IntegrationFlows.from(Jms.messageDrivenChannelAdapter(conFactory) .configureListenerContainer(c -> c.sessionTransacted(true)) .destination(myQueue) .errorChannel(myErrorChannel)) .handle(myHandler) .get(); } @Bean IntegrationFlow myErrorHandlingFlow() { return IntegrationFlows.from(myErrorChannel) .handle(myErrorHandler) .get(); }
该配置抑制了WARN日志及堆栈,但消息不再回滚和重新投递/处理。
请问是否存在一种方式,既能使用自定义错误处理器(自定义异常日志方式),同时保留事务回滚和消息重新投递?(注:我曾尝试在myErrorHandler中重新抛出异常,但又回到了原有的WARN+堆栈日志的行为。)
解决方案
要实现自定义日志且保留事务回滚、消息重投,需要绕过Spring Integration的errorChannel,直接给JMS监听容器配置自定义ErrorHandler,具体步骤如下:
- 自定义
ErrorHandler实现,在其中完成自定义日志逻辑后必须抛出异常,确保容器触发事务回滚:
@Component public class CustomJmsErrorHandler implements ErrorHandler { private static final Logger logger = LoggerFactory.getLogger(CustomJmsErrorHandler.class); @Override public void handleError(Throwable t) { // 针对预期的特定异常做自定义日志输出 if (t.getCause() instanceof YourExpectedException) { logger.info("检测到预期异常,将回滚消息并重试: {}", t.getMessage()); } else { // 非预期异常按原有级别记录日志 logger.warn("JMS消息处理失败: {}", t.getMessage(), t); } // 必须抛出异常,JMS容器才会执行事务回滚和消息重投 throw new RuntimeException(t); } }
- 在JMS消息驱动通道适配器的容器配置中注入自定义
ErrorHandler,不要配置errorChannel:
@Bean IntegrationFlow myFlow(CustomJmsErrorHandler customJmsErrorHandler) { return IntegrationFlows.from(Jms.messageDrivenChannelAdapter(conFactory) .configureListenerContainer(c -> c.sessionTransacted(true) .errorHandler(customJmsErrorHandler)) // 直接给容器绑定自定义ErrorHandler .destination(myQueue)) .handle(myHandler) .get(); }
原理说明
- 当配置
errorChannel时,Spring Integration会捕获异常并发送到错误通道,JMS容器会认为异常已被处理,不会触发事务回滚。 - 直接给JMS监听容器设置
ErrorHandler,异常会被容器捕获,自定义处理后抛出的异常会触发容器的事务回滚逻辑,同时使用自定义日志逻辑,不会输出默认的WARN日志。
内容的提问来源于stack exchange,提问作者Yaneek
相关产品推荐
相关产品推荐

