重试机制实现总结

原生方法

@Override
public String helloRerty(String msg) throws InterruptedException {
    int times = 0;
    while (times < 3) {
        try {
            if (msg.equals("error")) {
                throw new RuntimeException("error");
            }
        } catch (Exception e) {
            times++;
            log.info("times:{},time:{}", times, LocalDateTime.now());
            if (times == 3) {
                throw new RuntimeException("超过重试次数");
            }
            Thread.sleep(5000);
        }
    }

    return msg;
}

动态代理

/**
 * @Author shangkaihui
 * @Date 2020/5/23 19:28
 * @Desc 动态代理实现重试
 */
@Slf4j
public class RetryInvocationHandler implements InvocationHandler {

    private Object realTarget;

    public RetryInvocationHandler(Object realTarget) {
        this.realTarget = realTarget;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        int times = 0;
        while (times < 3) {
            try {
                return method.invoke(realTarget, args);
            } catch (Exception e) {
                times++;
                log.info("times:{},time:{}", times, LocalDateTime.now());
                if (times >= 3) {
                    throw new RuntimeException("超过超时次数");
                }
                Thread.sleep(1000);
            }
        }

        return null;
    }

    /**
     * 获取动态代理
     * @return
     */
    public static Object getProxy(Object realSubject) {
        InvocationHandler handler = new RetryInvocationHandler(realSubject);
        return Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);
    }
}

CGLIB代理

/**
 * @Author shangkaihui
 * @Date 2020/5/23 22:26
 * @Desc
 */
@Slf4j
public class RetryCglibInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        int times = 0;
        while (times < 3) {
            try {
                return methodProxy.invokeSuper(o, objects);
            } catch (Exception e) {
                times++;
                log.info("times:{},time:{}", times, LocalDateTime.now());
                if (times >= 3) {
                    throw new RuntimeException("超过重试次数");
                }
                Thread.sleep(1000);
            }
        }
        return null;
    }

    public  Object getProxy(Class clazz) {
        Enhancer enhancer = new Enhancer();
        //目标对象类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码技术创建目标对象类的子类实例作为代理
        return enhancer.create();
    }
}

注解+AOP实现

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Retry {

    /**
     * 重试次数
     * @return
     */
    int maxTimes() default  3;

    /**
     * 休眠时间
     * @return
     */
    int sleepTime() default 1000;
}
@Component
@Aspect
@Slf4j
public class RetryAspect {

    @Pointcut(value = "@annotation(com.example.demo.retry.Retry)")
    public void myPointcut() {
    }

    @Around("myPointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        //获取注解
        MethodSignature signature = (MethodSignature)point.getSignature();
        Method method = signature.getMethod();
        Retry retry = method.getAnnotation(Retry.class);
        int maxTime = retry.maxTimes();
        int sleepTime = retry.sleepTime();
        int times = 0;
        while (times < maxTime) {
            try {
                return point.proceed();

            } catch (Exception e) {
                times++;
                log.info("times:{},time:{}", times, LocalDateTime.now());
                if (times >= maxTime) {
                    throw new RuntimeException("超过超时次数");
                }
                Thread.sleep(sleepTime*times);
            }
        }
        return null;
    }

}

Spring Retry

pom引入

<dependency>
  <groupId>org.springframework.retry</groupId>
  <artifactId>spring-retry</artifactId>
</dependency>

应用启动类开启retry

@EnableRetry
public class Application {
    .......
}

在指定方法上标记@Retryable来开启重试

@Retryable(value={A异常.class,B异常.class},
     maxAttempts=重试次数,
     backoff = @Backoff(delay = 延迟毫秒数,multiplier = 延迟倍数))
public void retryTest() throws Exception {
    System.out.println(Thread.currentThread().getName()+" do something...");
    throw new RemoteAccessException("RemoteAccessException....");
}

在指定方法上标记@Recover来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中)

@Recover
  public void recover(A异常 e) {
    // ... do something
  }
  
  @Recover
  public void recover(B异常 e) {
    // ... do something
  }

注解参数详解

@Retryable注解:被注解的方法发生异常时会重试

value:指定发生的异常进行重试
include:和value一样,默认空,当exclude也为空时,所有异常都重试
exclude:指定异常不重试,默认空,当include也为空时,所有异常都重试
maxAttemps:重试次数,默认3
backoff:重试补偿机制,默认没有

@Backoff注解
delay:指定延迟后重试
multiplier:指定延迟的倍数,比如delay=5000l,multiplier=2时,第一次重试为5秒后,第二次为10秒,第三次为20秒

@Recover:当重试到达指定次数时,被注解的方法将被回调,可以在该方法中进行日志处理。需要注意的是发生的异常和入参类型一致时才会回调

代码示例

@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
@Async //开启异步
@Override
public String helloSpringRetry(String msg) {
    log.info("helloSpringRetry invoke...");
    if (msg.equals("error")) {
        log.info("helloSpringRetry invoke error...");
        throw new RuntimeException("error");
    }
    log.info("helloSpringRetry invoke success...");
    return msg;
}

/**
 * 回调方法,注意:该回调方法与重试方法写在同一个实现类里面
 * @return
 */
@Recover
public String recover(Exception e) {
    log.info("记录日志...",e);
    throw new RuntimeException("重试失败");
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值