@EnableRetry注解解读
dependency groupIdorg.springframework.retry/groupId artifactIdspring-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-retryConfiguration 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即指定延迟倍数比如delay5000l,multiplier2,则第一次重试为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 RetryCallbackFoo() { 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 是一把利器但需在理解其原理和限制的基础上谨慎使用方能真正提升系统的弹性。