异常重试机制/重试工具类,直接上代码
import java.util.Arrays;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 异常重试机制/重试工具类
*
* @Author: sun
* @Date: 2020-12-08 16:40
*/
public abstract class RetryWrap<T> {
private static final Logger logger = LoggerFactory.getLogger(RetryWrap.class);
private static final String taskName = "重试机制";
private String threadName;// 自定义线程名称
private int maxAttempts = 3; // 重试次数,默认3
private int nowAttempts = 0; // 当前重试次数,默认0
private long delay = 1000L; // 隔多少毫秒后重试,默认为1000L(1秒)
private double multiplier; // 延迟的倍数,比如delay=1000L,multiplier=2时,第一次重试为1秒后,第二次为2秒,第三次为4秒
public T execute() throws Exception {
long preSleepTime = 0L;
for (int i = 0; i <= maxAttempts; i++) {// 第0次请求表示首次执行,并非重试
this.nowAttempts = i;
try {
if (i != 0) {
logger.info(append(taskName, threadName, preSleepTime + " 毫秒后准备第 " + i + " 次重试"));
Thread.sleep(preSleepTime);
} else {
logger.info(append(taskName, threadName, "进入队列,首次执行"));
}
T result = todo();// 执行
if (i != 0) {
logger.info(append(taskName, threadName, "第 " + i + " 次重试执行已成功"));
} else {
logger.info(append(taskName, threadName, "首次执行已成功"));
}
return result;
} catch (Exception e) {
e.printStackTrace();
if (i == 0) {
logger.error(append(taskName, threadName, "首次执行", "出现异常", e.getMessage()));
preSleepTime = getDelay();
} else if (i == maxAttempts) {
logger.error(append(taskName, threadName, "第 " + i + " 次重试", "出现异常", e.getMessage()));
// 最后一次循环,将异常抛出
throw e;
} else {
logger.error(append(taskName, threadName, "第 " + i + " 次重试", "出现异常", e.getMessage()));
Double d = preSleepTime * getMultiplier();
preSleepTime = d.longValue();
}
}
}
return null;
}
/**
* 钩子
*/
protected abstract T todo() throws Exception;
/**
* 日志输出美化
*/
private String append(Object... params) {
return StringUtils.join(Arrays.asList(params).toArray(), "===>");
}
public int getMaxAttempts() {
return maxAttempts;
}
public RetryWrap<T> setMaxAttempts(int maxAttempts) {
this.maxAttempts = maxAttempts;
this.nowAttempts = maxAttempts;
return this;
}
public int getNowAttempts() {
return nowAttempts;
}
public long getDelay() {
return delay;
}
public RetryWrap<T> setDelay(long delay) {
this.delay = delay;
return this;
}
public double getMultiplier() {
return multiplier;
}
public RetryWrap<T> setMultiplier(double multiplier) {
this.multiplier = multiplier;
return this;
}
public String getThreadName() {
return threadName;
}
public RetryWrap<T> setThreadName(String threadName) {
this.threadName = threadName;
return this;
}
/**
* 测试案例
*
* @param args
*/
public static void main(String[] args) {
String result = null;
try {
result = new RetryWrap<String>() {
@Override
protected String todo() throws Exception {
int nowAttempts = this.getNowAttempts();
if (nowAttempts != 4) {// 重试三次都执行失败的测试
// if (nowAttempts != 3) {// 最后一次重试执行成功的测试
// Integer.valueOf("a");//运行时异常
throw new NullPointerException();// 非运行时程序异常,也有可能根据逻辑判断手动抛出自定义异常
}
return "SUCCESS";
}
}.setMaxAttempts(3).setDelay(1000L).setMultiplier(2).setThreadName("测试").execute();
logger.info("执行成功,跳出重试机制,打印执行结果", result);
} catch (Exception e) {
e.printStackTrace();
logger.info("执行失败", e.getMessage());
}
}
}
模拟执行,让最后一次重试执行成功,打印如下:
15:01:16.003 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:36) - 重试机制===>测试===>进入队列,首次执行
java.lang.NullPointerException
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:86)
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:1)
at com.xxxx.demo.RetryWrap.execute(RetryWrap.java:38)
at com.xxxx.demo.RetryWrap.main(RetryWrap.java:90)
15:01:16.020 [ERROR][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:48) - 重试机制===>测试===>首次执行===>出现异常===>
15:01:16.021 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:33) - 重试机制===>测试===>1000 毫秒后准备第 1 次重试
java.lang.NullPointerException
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:86)
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:1)
at com.xxxx.demo.RetryWrap.execute(RetryWrap.java:38)
at com.xxxx.demo.RetryWrap.main(RetryWrap.java:90)
15:01:17.024 [ERROR][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:55) - 重试机制===>测试===>第 1 次重试===>出现异常===>
15:01:17.025 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:33) - 重试机制===>测试===>2000 毫秒后准备第 2 次重试
java.lang.NullPointerException
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:86)
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:1)
at com.xxxx.demo.RetryWrap.execute(RetryWrap.java:38)
at com.xxxx.demo.RetryWrap.main(RetryWrap.java:90)
15:01:19.030 [ERROR][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:55) - 重试机制===>测试===>第 2 次重试===>出现异常===>
15:01:19.031 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:33) - 重试机制===>测试===>4000 毫秒后准备第 3 次重试
15:01:23.035 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:40) - 重试机制===>测试===>第 3 次重试执行已成功
15:01:23.035 [INFO][main] com.xxxx.demo.RetryWrap.main(RetryWrap.java:91) - 执行成功,跳出重试机制,打印执行结果===>SUCCESS
屏蔽main方法中的throw new NullPointerException(); 表示首次执行就成功,打印如下:
15:05:19.447 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:36) - 重试机制===>测试===>进入队列,首次执行
15:05:19.452 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:42) - 重试机制===>测试===>首次执行已成功
15:05:19.456 [INFO][main] com.xxxx.demo.RetryWrap.main(RetryWrap.java:91) - 执行成功,跳出重试机制,打印执行结果===>SUCCESS
重试全部都执行失败的情况下打印如下:
15:07:55.487 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:36) - 重试机制===>测试===>进入队列,首次执行
java.lang.NullPointerException
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:86)
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:1)
at com.xxxx.demo.RetryWrap.execute(RetryWrap.java:38)
at com.xxxx.demo.RetryWrap.main(RetryWrap.java:90)
15:07:55.504 [ERROR][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:48) - 重试机制===>测试===>首次执行===>出现异常===>
15:07:55.504 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:33) - 重试机制===>测试===>1000 毫秒后准备第 1 次重试
java.lang.NullPointerException
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:86)
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:1)
at com.xxxx.demo.RetryWrap.execute(RetryWrap.java:38)
at com.xxxx.demo.RetryWrap.main(RetryWrap.java:90)
15:07:56.509 [ERROR][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:55) - 重试机制===>测试===>第 1 次重试===>出现异常===>
15:07:56.509 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:33) - 重试机制===>测试===>2000 毫秒后准备第 2 次重试
java.lang.NullPointerException
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:86)
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:1)
at com.xxxx.demo.RetryWrap.execute(RetryWrap.java:38)
at com.xxxx.demo.RetryWrap.main(RetryWrap.java:90)
15:07:58.510 [ERROR][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:55) - 重试机制===>测试===>第 2 次重试===>出现异常===>
15:07:58.511 [INFO][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:33) - 重试机制===>测试===>4000 毫秒后准备第 3 次重试
java.lang.NullPointerException
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:86)
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:1)
at com.xxxx.demo.RetryWrap.execute(RetryWrap.java:38)
at com.xxxx.demo.RetryWrap.main(RetryWrap.java:90)
15:08:02.516 [ERROR][main] com.xxxx.demo.RetryWrap.execute(RetryWrap.java:51) - 重试机制===>测试===>第 3 次重试===>出现异常===>
java.lang.NullPointerException
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:86)
at com.xxxx.demo.RetryWrap$1.todo(RetryWrap.java:1)
at com.xxxx.demo.RetryWrap.execute(RetryWrap.java:38)
at com.xxxx.demo.RetryWrap.main(RetryWrap.java:90)
15:08:02.517 [INFO][main] com.xxxx.demo.RetryWrap.main(RetryWrap.java:94) - 执行失败===>