Spring中@Retryable重试后@Recover方法未触发问题求助
Spring Retry @Recover未触发的问题解决
核心问题与修复方案
1. 接口方法重试的代理限制
你的onMessage是实现MessageListener接口的方法,Spring Retry的代理机制(即使开启proxyTargetClass=true)在处理接口方法时,无法正确关联类内部的@Recover方法——因为代理对象只代理接口定义的方法,recover作为类的非接口方法不在代理范围内,导致重试结束后无法触发恢复逻辑。
修复方式:
将重试逻辑抽离为类的独立public方法,在接口实现方法中调用它:
@Slf4j @Component public class OpenAuditMessageReceiver implements MessageListener { @Autowired private MessageReceiver messageReceiver; @Override public void onMessage(Message message, byte[] pattern) { handleAuditMessage(message, pattern); } @SneakyThrows @Retryable(value = {SQLException.class}, maxAttempts = 2, backoff = @Backoff(delay = 2000)) public void handleAuditMessage(Message message, byte[] pattern) { try { log.info("OpenAuditMessageReceiver got {}", new String(message.getBody())); OpenAuditDTO openAuditDTO = messageReceiver.getObjectMapper().readValue(message.toString(), OpenAuditDTO.class); log.debug("Consumed - {}", openAuditDTO); messageReceiver.getAuditEntityRepository().insert(openAuditDTO); log.info("Successfully saved Audit Information"); } catch (Exception e){ log.error("Error occurred while handling {}", message, e); if(e instanceof SQLException){ throw e; } } } @Recover public void recover(SQLException e, Message message, byte[] pattern){ log.info("##### handle Recovery Mechanism #####"); } }
注意:Spring Retry仅能代理public方法,所以抽离后的方法必须是public权限。
2. 异常抛出的有效性检查
只有当@Retryable指定的异常(SQLException)被实际抛出时,重试逻辑才会触发,重试耗尽后才会走到@Recover。检查你的代码:
- 确认
insert方法确实会抛出SQLException(而非其子类以外的异常,或者被封装为RuntimeException) - 避免在catch块中吞掉
SQLException以外的、需要触发重试的异常(如果需要,可扩展@Retryable的value范围)
3. @Recover方法的匹配验证
@Recover方法必须满足参数匹配规则:
- 第一个参数必须是
@Retryable指定的异常类型(或其子类) - 后续参数必须与重试方法的参数完全一致(顺序、类型均需匹配)
你的recover方法参数符合要求,但需确保抛出的异常确实是SQLException及其子类。
内容的提问来源于stack exchange,提问作者IdanOst
相关产品推荐
相关产品推荐

