Java多用途重试工具
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 重试工具
*
* @author caochong
* @version 1.0
*/
public class RetryUtil {
public static class RetryException extends RuntimeException {
public RetryException() {
super();
}
public RetryException(String message, Throwable cause) {
super(message, cause);
}
public RetryException(String s) {
super(s);
}
}
public static class RetryResult {
// 是否重试
private boolean isRetry = false;
// 重试信息(需要重试时补充异常信息),用于收集内部异常
private String retryMsg;
public RetryResult(boolean isRetry) {
this.isRetry = isRetry;
}
public RetryResult(boolean isRetry, String retryMsg) {
this.isRetry = isRetry;
this.retryMsg = retryMsg;
}
}
/**
* 重试任务
*
* @param retryFunc 重试函数,此函数会循环调用(函数内全局变量请保证逻辑准确性)
* @param judgeFunc 重试判断函数,用于处理重试函数的结果来决策是否重试。返回 True重试
* @param errJudgeFunc 异常函数(当重试函数或重试判断函数异常时触发)。返回 True重试或抛出异常
* @param resultFunc 结果函数(重试成功时触发)。当存在异常且异常函数标识不再重试时,可能为NULL
* @param times 重试次数:首先执行一次,然后再重试times次
* @param intervalTime 每次重试间隔时间
* @param timeUnit 时间单位(默认:毫秒)
* @param intervalDoubly 试间隔时间倍增(2倍增加)
* @param <T> 每次重试的结果类型
* @param <R> 当重试成功时,最终返回的结果类型
* @return 当重试成功时,返回结果。当存在异常且异常函数标识不再重试时,可能为NULL
* @throws RetryException 重试异常,当重试次数达到最大时抛出该异常,线程中断异常
*/
public static <T, R> R retryProcess(Supplier<T> retryFunc, Function<T, RetryResult> judgeFunc,
Function<Exception, RetryResult> errJudgeFunc, Function<T, R> resultFunc,
int times, long intervalTime, TimeUnit timeUnit, boolean intervalDoubly) {
long sleepTime = timeUnit.toMillis(intervalTime);
int currentTimes = 0;
RetryResult retryResult;
T t = null;
List<String> errList = new ArrayList<>(0);
do {
currentTimes++;
try {
t = retryFunc.get();
retryResult = judgeFunc.apply(t);
} catch (Exception ex) {
if (errJudgeFunc != null) {
retryResult = errJudgeFunc.apply(ex);
} else {
throw ex;
}
}
if (retryResult == null) {
throw new RetryException("重试系统异常,重试状态不能为NULL");
}
if (!retryResult.isRetry) {
break;
}
// 收集异常
if (retryResult.retryMsg != null) {
errList.add(retryResult.retryMsg);
}
try {
Thread.sleep(sleepTime * (intervalDoubly ? currentTimes : 1));
} catch (InterruptedException ex) {
throw new RetryException(ex.getMessage(), ex);
}
} while (currentTimes <= times);
if (retryResult.isRetry) {
// 重试次数已达最大,结果处理
String errMsg = "调用异常";
if (!errList.isEmpty()) {
StringJoiner errMsgJoiner = new StringJoiner("|", "[", "]");
for (String msg : errList) {
errMsgJoiner.add(msg);
}
errMsg = errMsgJoiner.toString();
}
throw new RetryException("重试次数已达最大(" + times + "): " + errMsg);
} else {
// 重试成功结果
return resultFunc.apply(t);
}
}
/**
* 重试任务
*
* @param retryFunc 重试函数,此函数会循环调用(函数内全局变量请保证逻辑准确性)
* @param judgeFunc 重试判断函数,用于处理重试函数的结果来决策是否重试。返回 True重试
* @param errJudgeFunc 异常函数(当重试函数或重试判断函数异常时触发)。返回 True重试或抛出异常
* @param resultFunc 结果函数(重试成功时触发)。当存在异常且异常函数标识不再重试时,可能为NULL
* @param times 重试次数:首先执行一次,然后再重试times次
* @param intervalTime 每次重试间隔时间(默认:毫秒)
* @param <T> 每次重试的结果类型
* @param <R> 当重试成功时,最终返回的结果类型
* @return 当重试成功时,返回结果。当存在异常且异常函数标识不再重试时,可能为NULL
* @throws RetryException 重试异常,当重试次数达到最大时抛出该异常
*/
public static <T, R> R retryProcess(Supplier<T> retryFunc, Function<T, RetryResult> judgeFunc,
Function<Exception, RetryResult> errJudgeFunc, Function<T, R> resultFunc,
int times, long intervalTime) {
return retryProcess(retryFunc, judgeFunc, errJudgeFunc, resultFunc,
times, intervalTime, TimeUnit.MILLISECONDS, false);
}
/**
* 仅异常才进行任务重试
*
* @param retryFunc 重试函数,此函数会循环调用(函数内全局变量请保证逻辑准确性)
* @param errJudgeFunc 异常函数(当重试函数或重试判断函数异常时触发)。返回 True重试或抛出异常
* @param times 重试次数:首先执行一次,然后再重试times次
* @param intervalTime 每次重试间隔时间
* @param timeUnit 时间单位(默认:毫秒)
* @param intervalDoubly 试间隔时间倍增(2倍增加)
* @param <T> 每次重试的结果类型
* @return 当重试成功时,返回结果。当存在异常且异常函数标识不再重试时,可能为NULL
* @throws RetryException 重试异常,当重试次数达到最大时抛出该异常,线程中断异常
*/
public static <T> T retryProcess(Supplier<T> retryFunc, Function<Exception, RetryResult> errJudgeFunc, int times,
long intervalTime, TimeUnit timeUnit, boolean intervalDoubly) {
return retryProcess(retryFunc, t -> new RetryResult(false), errJudgeFunc, t -> t,
times, intervalTime, timeUnit, intervalDoubly);
}
/**
* 重试任务
*
* @param retryFunc 重试函数,此函数会循环调用(函数内全局变量请保证逻辑准确性)
* @param judgeFunc 重试判断函数,用于处理重试函数的结果来决策是否重试。返回 True重试
* @param resultFunc 结果函数(重试成功时触发)。当存在异常且异常函数标识不再重试时,可能为NULL
* @param times 重试次数:首先执行一次,然后再重试times次
* @param intervalTime 每次重试间隔时间(默认:毫秒)
* @param <T> 每次重试的结果类型
* @param <R> 当重试成功时,最终返回的结果类型
* @return 当重试成功时,返回结果。当存在异常且异常函数标识不再重试时,可能为NULL
* @throws RetryException 重试异常,当重试次数达到最大时抛出该异常
*/
public static <T, R> R retryProcess(Supplier<T> retryFunc, Function<T, RetryResult> judgeFunc,
Function<T, R> resultFunc, int times,
long intervalTime, TimeUnit timeUnit) {
return retryProcess(retryFunc, judgeFunc, null, resultFunc,
times, intervalTime, timeUnit, false);
}
/**
* 重试任务
*
* @param retryFunc 重试函数,此函数会循环调用(函数内全局变量请保证逻辑准确性)
* @param judgeFunc 重试判断函数,用于处理重试函数的结果来决策是否重试。返回 True重试
* @param resultFunc 结果函数(重试成功时触发)。当存在异常且异常函数标识不再重试时,可能为NULL
* @param times 重试次数:首先执行一次,然后再重试times次
* @param intervalTime 每次重试间隔时间(默认:毫秒)
* @param <T> 每次重试的结果类型
* @param <R> 当重试成功时,最终返回的结果类型
* @return 当重试成功时,返回结果。当存在异常且异常函数标识不再重试时,可能为NULL
* @throws RetryException 重试异常,当重试次数达到最大时抛出该异常
*/
public static <T, R> R retryProcess(Supplier<T> retryFunc, Function<T, RetryResult> judgeFunc,
Function<T, R> resultFunc, int times, long intervalTime) {
return retryProcess(retryFunc, judgeFunc, resultFunc, times, intervalTime, TimeUnit.MILLISECONDS);
}
/**
* 重试任务
*
* @param retryFunc 重试函数,此函数会循环调用(函数内全局变量请保证逻辑准确性)
* @param judgeFunc 重试判断函数,用于处理重试函数的结果来决策是否重试。返回 True重试
* @param times 重试次数:首先执行一次,然后再重试times次
* @param intervalTime 每次重试间隔时间(默认:毫秒)
* @param <T> 每次重试的结果类型
* @return 当重试成功时,返回结果。当存在异常且异常函数标识不再重试时,可能为NULL
* @throws RetryException 重试异常,当重试次数达到最大时抛出该异常
*/
public static <T> T retryProcess(Supplier<T> retryFunc, Function<T, RetryResult> judgeFunc,
int times, long intervalTime) {
return retryProcess(retryFunc, judgeFunc, t -> t, times, intervalTime);
}
public static void main(String[] args) {
final Integer[] val = {0};
Integer result = retryProcess(() -> {
val[0] = val[0] + 1;
return val[0];
}, (t) -> {
System.out.println(t + ":" + System.currentTimeMillis());
return new RetryResult(t < 5);
}, null, (t) -> t,
5, 300L, TimeUnit.MILLISECONDS, true);
System.out.println("result: " + result);
}
}