设为首页 加入收藏

TOP

Java 中的 7 种重试机制,还有谁不会?!(三)
2023-08-26 21:11:23 】 浏览:105
Tags:Java
000, multiplier = 2)) public void addOrder() { System.out.println("重试..."); int i = 3 / 0; // addOrder } @Recover public void recover(RuntimeException e) { log.error("达到最大重试次数", e); } }

该方法调用后会进行重试,最大重试次数为 3,第一次重试间隔为 2s,之后以 2 倍大小进行递增,第二次重试间隔为 4 s,第三次为 8s

Spring 的重试机制还支持很多很有用的特性,由三个注解完成:

  • @Retryable
  • @Backoff
  • @Recover

查看 @Retryable 注解源码:指定异常重试、次数

public @interface Retryable {

 // 设置重试拦截器的 bean 名称
    String interceptor() default "";
 
 // 只对特定类型的异常进行重试。默认:所有异常
    Class<? extends Throwable>[] value() default {};
 
 // 包含或者排除哪些异常进行重试
    Class<? extends Throwable>[] include() default {};
    Class<? extends Throwable>[] exclude() default {};
 
 // l设置该重试的唯一标志,用于统计输出
    String label() default "";

    boolean stateful() default false;
 
 // 最大重试次数,默认为 3 次
    int maxAttempts() default 3;
 
 
    String maxAttemptsExpression() default "";
 
 // 设置重试补偿机制,可以设置重试间隔,并且支持设置重试延迟倍数
    Backoff backoff() default @Backoff;
 
 // 异常表达式,在抛出异常后执行,以判断后续是否进行重试
    String exceptionExpression() default "";

    String[] listeners() default {};
}

@Backoff 注解: 指定重试回退策略(如果因为网络波动导致调用失败,立即重试可能还是会失败,最优选择是等待一小会儿再重试。决定等待多久之后再重试的方法。通俗的说,就是每次重试是立即重试还是等待一段时间后重试)

@Recover 注解: 进行善后工作:当重试达到指定次数之后,会调用指定的方法来进行日志记录等操作

注意:
  • @Recover 注解标记的方法必须和被 @Retryable 标记的方法在同一个类中
  • 重试方法抛出的异常类型需要与 recover() 方法参数类型保持一致
  • recover() 方法返回值需要与重试方法返回值保证一致
  • recover() 方法中不能再抛出 Exception,否则会报无法识别该异常的错误

这里还需要再提醒的一点是,由于 Spring Retry 用到了 Aspect 增强,所以就会有使用 Aspect 不可避免的坑——方法内部调用,如果被 @Retryable 注解的方法的调用方和被调用方处于同一个类中,那么重试将会失效

通过以上几个简单的配置,可以看到 Spring Retry 重试机制考虑的比较完善,比自己写AOP实现要强大很多

弊端:

但也还是存在一定的不足,Spring的重试机制只支持对 异常 进行捕获,而无法对返回值进行校验

@Retryable
public String hello() {
    long current = count.incrementAndGet();
    System.out.println("第" + current +"次被调用");
    if (current % 3 != 0) {
        log.warn("调用失败");
        return "error";
    }
    return "success";
}

因此就算在方法上添加 @Retryable,也无法实现失败重试

除了使用注解外,Spring Retry 也支持直接在调用时使用代码进行重试:

@Test
public void normalSpringRetry() {
    // 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试
    Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
    exceptionMap.put(HelloRetryException.class, true);
 
    // 构建重试模板实例
    RetryTemplate retryTemplate = new RetryTemplate();
 
    // 设置重试回退操作策略,主要设置重试间隔时间
    FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
    long fixedPeriodTime = 1000L;
    backOffPolicy.setBackOffPeriod(fixedPeriodTime);
 
    // 设置重试策略,主要设置重试次数
    int maxRetryTimes = 3;
    SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
 
    retryTemplate.setRetryPolicy(retryPolicy);
    retryTemplate.setBackOffPolicy(backOffPolicy);
 
    Boolean execute = retryTemplate.execute(
        //RetryCallback
        retryContext -> {
            String hello = helloService.hello();
            log.info("调用的结果:{}", hello);
            return true;
        },
        // RecoverCallBack
        retryContext -> {
            //RecoveryCallback
            log.info("已达到最大重试次数");
            return false;
        }
    );
}

此时唯一的好处是可以设置多种重试策略:

  • NeverRetryPolicy:只允许调用RetryCallback一次,不允许重试
  • AlwaysRetryPolicy:允许无限重试,直到成功,此方式逻辑不当会导致死循环
  • SimpleRetryPolicy:固定次数重试策略,默认重试最大次数为3次,RetryTemplate默认使用的策略
  • TimeoutRetryPolicy:超时时间重试策略,默认超时时间为1秒,在指定的超时时间内允许重试
  • ExceptionClassifierRetryPolicy:设置不同异常的重试策略,类似组合重试策略,区别在于这里只区
首页 上一页 1 2 3 4 下一页 尾页 3/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇SpringBoot入门 下一篇9、Spring之代理模式

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目