Spring Retry
重试
重试是指当一个程序运行过程中,遇到网络延迟、中断等情况时,为了保证程序容错性、可用性、一致性等一个措施。
简介
Spring Retry 是一套 Spring 实现的一套重试机制,主要功能点在于重试和熔断。它被广泛用于Spring Batch,Spring Integration, Spring for Apache Hadoop 等项目。它主要是针对可能抛异常的一些调用操作,进行有策略的重试
Spring Retry 提供了 注解 和 编程 的两种支持,提供了 RetryTemplate 的支持

使用
Spring Retry 编程式
导入依赖
1 2 3 4
| <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>
|
自定义异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class RemoteAccessException extends RuntimeException {
public RemoteAccessException(String message) { super(message); }
public RemoteAccessException(String message, Throwable cause) { super(message, cause); }
public RemoteAccessException(Throwable cause) { super(cause); } }
|
任务方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class RetryTask {
private static final Logger logger = LoggerFactory.getLogger(RetryTask.class);
public static boolean task() { logger.info("开启重试任务"); Random random = new Random(); switch (random.nextInt(4)) { case 0: logger.info("抛出异常"); throw new IllegalArgumentException("参数异常"); case 1: logger.info("正确返回"); return true; case 2: logger.info("错误返回"); return false; default: logger.info("抛出自定义异常"); throw new RemoteAccessException("远程访问异常"); } } }
|
使用 SpringRetryTemplate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| @RunWith(SpringRunner.class) @SpringBootTest public class SpringDemoRetryTest {
private Logger logger = LoggerFactory.getLogger(SpringDemoRetryTest.class);
private Long retryInterval = 1000L;
private int maxRetryTimes = 3;
@Test public void test() throws Throwable {
RetryTemplate retryTemplate = new RetryTemplate();
Map<Class<? extends Throwable>, Boolean> retryableExceptions = new HashMap<>(); retryableExceptions.put(RemoteAccessException.class, true);
SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy(maxRetryTimes, retryableExceptions);
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); fixedBackOffPolicy.setBackOffPeriod(retryInterval);
retryTemplate.setRetryPolicy(simpleRetryPolicy); retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
Boolean execute = retryTemplate.execute( context -> { boolean task = RetryTask.task(); logger.info("调用的结果:{}", task); return task; }, context -> { logger.info("已经达到最大重试次数或者抛出不重试的异常"); return false; } ); logger.info("执行结果:{}", execute); } }
|
RetryTemplate 承担了重试执行者的角色,它可以设置RetryPolicy(重试策略),BackOffPolicy(固定的回退策略)
RetryTemplate通过execute提交执行操作,需要准备RetryCallback 和BackOffPolicy 两个类实例
RetryCallback 是重试回调逻辑实例,包装正常的功能操作,RecoveryCallback实现的是整个执行操作结束的恢复操作实例
只有在调用的时候抛出了异常,并且异常是在exceptionMap中配置的异常,才会执行重试操作,否则就调用到excute方法的第二个执行方法RecoveryCallback中
重试策略


重试回退策略


Spring Retry 声明式
导入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13
| <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency>
|
开启注解
1 2 3 4 5 6 7
| @SpringBootApplication @EnableRetry public class SpringDemoRetry { public static void main(String[] args) { SpringApplication.run(SpringDemoRetry.class, args); } }
|
添加注解
我们只要在需要重试的方法上加@Retryable,在重试失败的回调方法上加@Recover

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public interface SpringRetryService {
boolean call();
boolean recover(Exception e); }
@Service public class SpringRetryServiceImpl implements SpringRetryService {
private static final Logger logger = LoggerFactory.getLogger(SpringRetryServiceImpl.class);
@Override @Retryable(value = {RemoteAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 2)) public boolean call() { return RetryTask.task(); }
@Override @Recover public boolean recover(Exception e) { logger.error("达到最大重试次数,或抛出了一个没有指定进行重试的异常:", e); return false; } }
|
@Retryable 表示 RemoteAccessException 的异常才进行重试,@Backoff(delay = 2000L, multiplier = 2)) 表示第一次间隔2秒,以后都是次数的2倍,也就是第二次4秒,第三次6秒
调用测试类
1 2 3 4 5 6
| @Test public void test2() {
boolean call = springRetryService.call(); logger.info("--结果:{}--", call); }
|
[https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247556669&idx=2&sn=a41ac98ab32cb482588b9059773b54fb&chksm=fa4a618ccd3de89a63cb99c44077302da698ec6c9ac0870783cd12df62002416d522a5267e42&mpshare=1&scene=24&srcid=0617EnhGZStTL20lp7GJvG2x&sharer_sharetime=1687010876772&sharer_shareid=470e895f697284625270102fdb3d1bae#rd]: “重试框架 Spring-Retry 和 Guava-Retry,你知道该怎么选吗?”
[https://juejin.cn/post/7234107489390116925]: “spring-retry详解”