Java 自制重试机制(通用的异常重试工具类)

发布时间:2020-12-09作者:laosun阅读(2237)

Java 自制重试机制(通用的异常重试)

    异常重试机制/重试工具类

    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) - 执行失败===>


3 +1

版权声明

 Java  源码  开源

 请文明留言

0 条评论