@EnableRetry注解解读
2026/8/29 11:56:39 网站建设 项目流程
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>

前言

在分布式系统、微服务架构以及对外部服务(如数据库、第三方API、消息队列)的调用中,网络抖动、服务瞬时不可用、资源竞争等导致的临时性失败是常见现象。简单的一次性失败重试可能引发“惊群效应”,而完全放弃重试则会降低系统可用性。Spring Retry 正是为解决这类问题而生的声明式重试框架,它允许开发者以注解或编程方式,对可能失败的操作配置灵活的重试策略、退避机制和兜底恢复逻辑,从而提升系统的健壮性和容错能力。

本文将详细介绍 Spring Retry 的核心概念、注解用法与编程式 API,帮助读者在项目中快速引入并正确配置重试逻辑,避免因不当使用导致的资源耗尽、雪崩等问题。

一、概念
spring对于重试机制的实现,给了几个抽象。

BackOff:补偿值,一般指失败后多久进行重试的延迟值。
Sleeper:暂停应用的工具,通常用来应用补偿值。
BackOffPolicy:补偿策略,决定失败后如何确定补偿值。
RetryContext:重试上下文,代表了能被重试动作使用的资源。
RetryPolicy:重试策略,决定失败能否重试。
RecoveryCallback:定义一个动作recover,在重试耗尽后的动作。
RetryCallback:具体的重试动作。
RetryOperations:通过传递RetryCallback,进行重试操作。
RetryState:重试状态,通常包含一个重试的键值。
RetryStatistics和RetryListener,用来监控Retry的执行情况,并生成统计信息。

github地址:GitHub - spring-projects/spring-retry

@Configuration @EnableRetry public class Application { @Bean public Service service() { return new Service(); } } @Service class Service { @Retryable(RemoteAccessException.class) public void service() { // ... do something } //spring-retry @Recover不执行2个方法返回值一致就ok了 //返回值和@Retryable的返回值一致,入参和抛出异常一致 @Recover public void recover(RemoteAccessException e) { // ... panic } }

通过@EnableRetry就可以启用Retry功能了,需要被重试的方法加上@Retryable(),就能在指定的异常出现情况下重试,而当默认的失败次数到达后(查看SimpleRetryPolicy可知,就是试3次),就会调用@Recover注解的方法,进行恢复。
当然在@Retryable上,可以配置属性,更加细化
例如:@Retryable(value= {RemoteAccessException.class},maxAttempts = 5,backoff = @Backoff(delay = 5000l,multiplier = 1))
指定,重试5次,每次补偿(延迟5秒),每次倍数为1(不变)。

几个注解的参数解释

@EnableRetry能否重试。当proxyTargetClass属性为true时,使用CGLIB代理。默认使用标准JAVA注解。在spring Boot中此参数写在程序入口即可。
@Retryable 标注此注解的方法在发生异常时会进行重试

value:指定处理的异常类
include:指定处理的异常类和value一样,默认为空,当exclude也为空时,默认所有异常
exclude:指定异常不处理,默认空,当include也为空时,默认所有异常
maxAttempts:最大重试次数。默认3次
-backoff: 重试补偿策略。默认使用@Backoff注解
@Backoff 重试补偿策略

不设置参数时,默认使用FixedBackOffPolicy(指定等待时间),重试等待1000ms
设置delay,使用FixedBackOffPolicy(指定等待- - 设置delay和maxDealy时,重试等待在这两个值之间均态分布
设置delay、maxDealy、multiplier,使用 ExponentialBackOffPolicy(指数级重试间隔的实现 ),multiplier即指定延迟倍数,比如delay=5000l,multiplier=2,则第一次重试为5秒,第二次为10秒,第三次为20秒
@Recover 用于@Retryable重试失败后处理方法,此注解注释的方法参数一定要是@Retryable抛出的异常,否则无法识别,可以在该方法中进行日志处理。

三、核心API-RetryTemplate
声明式的使用,实际上是由spring-retry在内部生成了一个默认的RetryTemplate,由它封装我们自己写的函数完成的重试。这有点像@Scheduled,内部生成了一个ThreadPoolTaskExecutor完成定时任务的调度。虽然简单,但是可配置的东西太少了,如果想用spring-retry强大的策略机制,并必须定制化RetryTemplate。

官方的API使用demo如下:

RetryTemplate template = new RetryTemplate(); TimeoutRetryPolicy policy = new TimeoutRetryPolicy(); policy.setTimeout(30000L); template.setRetryPolicy(policy); Foo result = template.execute(new RetryCallback<Foo>() { public Foo doWithRetry(RetryContext context) { // Do stuff that might fail, e.g. webservice operation return result; } });


可以看出,new出一个RetryTemplate对象后,可以给它设置重试策略、补偿策略、重试监听器等属性。核心是在template.execute(),传递一个RetryCallback,内部执行我们需要重试的具体方法。
RetryTemplate是标准spring的××Template风格(脑补jdbcTemplate),内部doExecute()方法实现了如何开启重试上下文,获取补偿上下文,在try/catch中执行doWithRetry(),出现异常捕捉下来,如何应用重试策略决定重试,最后如何应用回退方法,关闭上下文等。这些都模板化了,我们只需要要传入RetryCallback和RecoveryCallback(连这个也可省)。

总结与注意事项

Spring Retry 为处理临时性失败提供了优雅的解决方案,但在使用时需要注意以下几点:

使用要点

  • 明确重试场景:仅对非幂等操作非业务逻辑错误(如网络超时、数据库连接中断)启用重试。对于参数错误、权限不足等业务异常,重试通常无效。
  • 合理配置重试策略:根据被调用服务的 SLA 和自身系统容忍度,设置合适的最大重试次数(maxAttempts)和退避策略(@Backoff),避免过度重试拖垮系统。
  • 结合断路器模式:在微服务架构中,建议将 Spring Retry 与 Resilience4j 或 Hystrix 等断路器框架结合使用。重试解决瞬时故障,断路器在服务持续不可用时快速失败,防止级联故障。
  • 做好日志与监控:通过RetryListener或自定义切面记录重试事件,便于问题排查和系统健康度评估。

常见坑点

  • 代理机制限制@Retryable基于 AOP 代理实现,因此自调用(同一个类中方法 A 调用方法 B,且 B 有@Retryable)会失效。需要通过注入代理对象或使用AopContext.currentProxy()解决。
  • 异常类型匹配@Recover方法的异常参数必须与@Retryable方法抛出的异常类型严格匹配(或为其父类),且返回值类型需一致,否则恢复方法不会被调用。
  • 上下文状态清理:在编程式使用RetryTemplate时,注意RetryContext的生命周期,避免在多线程环境下上下文状态污染。
  • 资源泄漏风险:长时间的重试等待(尤其是指数退避)可能占用连接、线程等资源。务必设置超时(TimeoutRetryPolicy)或使用异步重试(如结合@Async)。
  • 数据库事务与幂等性:在重试包含数据库写操作的业务时,需考虑事务边界和幂等性设计,防止重复提交导致数据不一致。

总之,Spring Retry 是一把利器,但需在理解其原理和限制的基础上谨慎使用,方能真正提升系统的弹性。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询