带@Scheduled的@Retryable方法对应的@Recover方法未触发问题排查
解决@Recover方法未随@Retryable触发的问题
我懂你这种查了一堆相关问题还是卡壳的感觉,咱们来一步步拆解你的代码里的问题,帮你让@Recover正常跑起来。
最核心的问题:@Scheduled和@Retryable的代理冲突
Spring的@Scheduled和@Retryable都是靠动态代理实现的,但如果把这两个注解加在同一个方法上,就会出现代理逻辑冲突——@Scheduled的代理会先接管方法执行,导致@Retryable的重试逻辑根本没被触发,那@Recover自然也不会执行。
解决方法:拆分定时任务和重试逻辑
把定时任务的调用和带重试的方法分开写,让重试逻辑在单独的方法里执行,这样两个代理就能各司其职了:
@Service public class MyRetryingService { @Scheduled(fixedRate = 10 * 1000) public void scheduledTransferTask() { // 调用带重试逻辑的方法 transferData(); } @Retryable(backoff = @Backoff(delay = 100, maxDelay = 101), maxAttempts = 3) public void transferData() { throw new IllegalArgumentException(); } @Recover public void recover(IllegalArgumentException exception) { System.out.println("Recovering from a service down"); } }
还要检查这两个配置细节
1. 确保Spring Retry的依赖和启用配置都到位
- 确认项目里已经引入了Spring Retry的依赖(比如Maven的
spring-retry和spring-aspects) - 在你的配置类上加上
@EnableRetry和@EnableScheduling注解,不然Spring根本不会识别重试和定时任务的逻辑:
@Configuration @EnableRetry @EnableScheduling public class AppConfig { // 其他配置内容 }
2. 核对@Recover方法的签名匹配
虽然你的@Recover方法参数看起来没问题,但还是要确认:
- @Recover方法的参数必须和@Retryable方法抛出的异常完全匹配(你的IllegalArgumentException是对的)
- @Recover方法的返回值要和@Retryable方法一致(都是void,这点没问题)
- 两个方法必须在同一个类中(你已经满足)
最后再验证一下
做完上面的修改后,启动项目,当transferData方法抛出异常时,Spring会重试3次,之后就会触发recover方法打印日志了。
内容的提问来源于stack exchange,提问作者Kamal Joshi
相关产品推荐
相关产品推荐

