使用场景:业务中经常遇到需要重试机制对一段代码进行 多次执行常遇到的有 访问网络数据接口,由于网络等原因需要重试 两到多次,直到返回正确结果为止。
已有方案:
1. guava-retrying 开源项目
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
2. spring-retry
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
以上两种方案都可以完美的解决 重试问题
但是上面两种方案都略显臃肿,需要依赖第三方项目(主要是没大看懂他们的源码),基于Java8 函数式编程(太香了)
开发一下工具Demo (只是个Demo,一种方案,可优化,求分享)
上代码:
package com.barton;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Supplier;
/**
* create by barton on 2020-6-30
*/
public class RetryTest {
/**
* 重试机制
* @param retryNumber 重试次数
* @param waitTime 重试等待时间
* @param retryIfExceptionType 重试一场类型
* @param call 执行主体
* @param retryIf 重试条件
* @param <T>
* @return T
*/
public static <T> T retry(
Integer retryNumber,
Long waitTime,
Class<? extends Throwable> retryIfExceptionType,
Supplier<T> call,
BiFunction<Integer,T,Boolean> retryIf
){
T result = null;
Integer currentNumber = 1;
Boolean exceptionFlag = false;
while (true){
if(currentNumber > retryNumber){
return result;
}
exceptionFlag = false;
try{
result = call.get();
}catch (Exception e){
if(retryIfExceptionType != null
&& e.getClass().getName().equals(retryIfExceptionType.getName())){
exceptionFlag = true;
}
e.printStackTrace();
}
if(exceptionFlag){
currentNumber++;
continue;
}
if(retryIf != null){
Boolean isRetry = retryIf.apply(currentNumber,result);
// true 重试,false 不重试返回
if(!isRetry){
return result;
}else {
//间隔一定时间重试
if(waitTime != null && waitTime > 0){
try {
TimeUnit.MILLISECONDS.sleep(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
currentNumber++;
}
}
public static void main(String[] args) {
String res = retry(3,
2000L,
NumberFormatException.class,
()->{
// 执行主体
System.out.println("do something");
return "SUCCESS";
},(number,result)->{
System.out.println("retry:"+number);
// 判断是否需要重试,根据业务修改
if("SUCCESS".equals(result)){
return true;
}else{
return false;
}
});
System.out.println(res);
}
}
(注:只是个Demo ,需要使用的同学可优化,欢迎分享)