springboot 实现重试逻辑
有时候业务需求,我们需要将一些接口重复的请求,当前端多次调用不太合适的时候。那么我们可以自己调用相关业务。
在什么情况下可以重试
1、远程调用超时、网络突然中断可以重试
2、外部 RPC 调用,如果一次操作失败,可以进行多次重试
3、提高调用成功的可能性
优雅的重试机制要具备几点
无侵入:不改动当前的业务逻辑,对于需要重试的地方,可以很简单的实现
可配置:包括重试次数,重试的间隔时间,是否使用异步方式
通用性:最好是无改动(或者很小改动)的支持绝大部分的场景,拿过来直接可用
导入依赖
<!--重试机制-->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
注意:这我指定了spring-retry的版本,因为我们使用@Retryable增加recover属性是1.3版本之后,之前是没有这个属性的
启用重试机制 (在启动类中加入 @EnableRetry)
注解@Retryable
被注解的方法发生异常时会重试
value:指定发生的异常进行重试
include:和value一样,默认空,当exclude也为空时,所有异常都重试
exclude:指定异常不重试,默认空,当include也为空时,所有异常都重试
maxAttemps:重试次数,默认3
backoff:重试补偿机制,默认没有
recover:指定异常调用方法名称
listeners:监听类
注解 @Backoff
delay:指定延迟后重试
multiplier:指定延迟的倍数,比如delay=5000l,multiplier=2时,第一次重试为5秒后,第二次为10秒,第三次为20秒
注解 @Recover
当重试到达指定次数时,被注解的方法将被回调,可以在该方法中进行日志处理。需要注意的是发生的异常和入参类型一致时才会回调
使用完整示例
/**
* 重试机制测试
* @return
*/
@Override
@Retryable( recover ="recoverSdDirectMailBill",value= BusinessException.class,maxAttempts = 3,listeners = {"defaultRetryListener"},backoff = @Backoff(value = 2000, multiplier = 2))
public void replayMethods() {
log.info("数据执行.......");
int code=0;
try {
int i=1/0;
}catch (Exception e){
throw new BusinessException(123,"错误提示");
}
}
@Recover
public void recoverSdDirectMailBill(BusinessException exception) {
log.info("数据异常.......{}");
log.info("异常信息.......{}");
}
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.stereotype.Service;
/**
* @author lilinchun
* @date 2022/4/14 0014 14:39
*/
@Service
public class DefaultRetryListener implements RetryListener {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
System.out.println("==前置回调==");
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
System.out.println("==后置回调==");
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
System.out.println("==执行报错==");
}
}
执行结果
注意小细节指定的回调方法必须返回参数是一致的抛出的异常也要是同一个异常
如果不使用指定的回调方法将recover ="recoverSdDirectMailBill"去掉就可以了
如果你想让所有的重试方法都使用同一个回调方法那么就只需要使用它默认的方法就可以了
@Recover
public void recover(BusinessException exception) {
log.info("数据异常.......{}");
log.info("异常信息.......{}");
}