使用Spring Retry增加业务的健壮性
前言
我维护的一个项目里,经常会遇到一个错误,每一次业务场景都需要生成一个唯一的业务id,有一个专门生成业务id的序列化服务,业务服务会频繁调用这个序列化服务,因为序列化服务的代码并非我开发的,并且它依赖的组件版本有点旧,所以我得想办法解决这个问题,并且尽量在我自己维护的业务模块里做改动。
所以我在我得代码里增加了重试机制,如果请求序列化服务报错,那就重新发送请求。
Spring Retry
加重试机制很简单,将同样的代码copy一份,或者抽出来做成一个函数,调用多次就好。
但是这样不够优雅,而Spring Retry提供了一个优雅的方案来自动重试。下面讲讲Spring Retry的简单用法
添加依赖
使用Spring Retry除了要添加它本身的依赖之外,还需要添加spring-aspects依赖,因为retry机制底层是通过aop来实现的。
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
启用Retry
在SpringBoot配之类里增加@EnableRetry注解
@Retryable 注解
在业务代码中为需要重试的方法添加@Retryable注解
例子:
@Retryable(value = RuntimeException.class, maxAttempts = 3)
public int testRetry() {
int rand = RandomUtil.randomInt(10);
System.out.println("random number: " + rand);
if (rand > 3) {
throw new RuntimeException("Random number is greater than 5");
}
return rand;
}
@Recover 注解
如果重试一直失败,我们需要一个补偿机制,这时候加了@Recover注解的方法就是这个补偿机制
@Recover
public int recover(RuntimeException e) {
return -1;
}
另外,@Retryable注解里也需要指明使用哪一个Recover方法
@Retryable(value = RuntimeException.class, maxAttempts = 3, recover = "recover")
完整的示例代码:
package com.example.demoground.service;
import cn.hutool.core.util.RandomUtil;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@Service
public class RetryService {
@Retryable(value = RuntimeException.class, maxAttempts = 3, recover = "recover")
public int testRetry() {
int rand = RandomUtil.randomInt(10);
System.out.println("random number: " + rand);
if (rand > 3) {
throw new RuntimeException("Random number is greater than 5");
}
return rand;
}
@Recover
public int recover(RuntimeException e) {
return -1;
}
}