如何配置JMS容器工厂实现退避重试且不重试MessageConversionException
问题解答
问题1:指数退避重试配置不生效
你的ExponentialBackOffWithMaxRetries未生效的核心原因是Spring JMS的DefaultJmsListenerContainerFactory需要结合RetryTemplate才能启用自定义重试退避策略,单纯调用setBackOff()无法触发指数退避逻辑,默认会使用内置的SimpleRetryPolicy(默认10次重试、间隔1秒)。此外,configurer.configure(factory, connectionFactory)会应用Spring Boot自动配置,可能覆盖你提前设置的重试属性,需调整配置顺序。
修复代码
@Bean fun jmsListenerContainerFactory( connectionFactory: ConnectionFactory, configurer: DefaultJmsListenerContainerFactoryConfigurer ): JmsListenerContainerFactory<*> { val factory = DefaultJmsListenerContainerFactory() // 先执行自动配置,再覆盖自定义重试规则 configurer.configure(factory, connectionFactory) // 配置指数退避策略 val backOffPolicy = ExponentialBackOffWithMaxRetries(5).apply { initialInterval = 1000 maxInterval = 10000 multiplier = 1.5 } // 配置重试模板,关联重试次数与退避策略 val retryTemplate = RetryTemplate().apply { setRetryPolicy(SimpleRetryPolicy(5)) setBackOffPolicy(backOffPolicy) } factory.setRetryTemplate(retryTemplate) factory.setErrorHandler(ContainerFactoryErrorHandler()) return factory }
注意:如果使用Azure Service Bus JMS,部分重试行为可能由服务端策略控制,需确保客户端未启用服务端重试(可通过Azure配置调整)。
问题2:捕获无效JSON消息并阻止重试
该需求完全可行,但需调整逻辑:MessageConversionException发生在监听器方法调用前的消息转换阶段,容器会优先触发重试逻辑,再调用ErrorHandler。仅在ErrorHandler中不抛出异常无法阻止重试,需在重试策略中排除该异常类型,让容器直接跳过重试进入错误处理。
修复方案
- 调整重试策略,排除
MessageConversionException
val retryPolicy = SimpleRetryPolicy().apply { // 仅允许RuntimeException触发重试 val retryableExceptions = mapOf( RuntimeException::class.java to true ) setRetryableExceptions(retryableExceptions) } val retryTemplate = RetryTemplate().apply { setRetryPolicy(retryPolicy) setBackOffPolicy(backOffPolicy) }
- 保留
ContainerFactoryErrorHandler逻辑,处理无效消息
class ContainerFactoryErrorHandler : ErrorHandler { private val logger = LoggerFactory.getLogger(javaClass) override fun handleError(t: Throwable) { when { t.cause is MessageConversionException -> { logger.error("无效JSON消息,已丢弃", t) // 不抛出异常,终止重试流程 } else -> { // 重新抛出异常,触发重试(符合重试策略的情况) throw t } } } }
内容的提问来源于stack exchange,提问作者Wall-E
相关产品推荐
相关产品推荐

