• Java-重试机制


    介绍

    在很多业务场景中,为了排除系统中的各种不稳定因素,以及逻辑上的错误,并最大概率保证获得预期的结果,重试机制都是必不可少的。

    尤其是调用远程服务,在高并发场景下,很可能因为服务器响应延迟或者网络原因,造成我们得不到想要的结果,或者根本得不到响应。这个时候,一个优雅的重试调用机制,可以让我们更大概率保证得到预期的响应。

    一个完备的重试实现,要很好地解决如下问题: 1. 什么条件下重试 2. 什么条件下停止 3. 如何停止重试 4. 停止重试等待多久 5. 如何等待 6. 请求时间限制 7. 如何结束 8. 如何监听整个重试过程

    guava-retrying(谷歌)

    <dependency>
        <groupId>com.github.rholdergroupId>
        <artifactId>guava-retryingartifactId>
        <version>2.0.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    完整的参考实现

    public Boolean test() throws Exception {
        //定义重试机制
        Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                //retryIf 重试条件
                .retryIfException()
                .retryIfRuntimeException()
                .retryIfExceptionOfType(Exception.class)
                .retryIfException(Predicates.equalTo(new Exception()))
                .retryIfResult(Predicates.equalTo(false))
    
                //等待策略:每次请求间隔1s
                .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
    
                //停止策略 : 尝试请求6次
                .withStopStrategy(StopStrategies.stopAfterAttempt(6))
    
                //时间限制 : 某次请求不得超过3s 否则重试
                .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(3, TimeUnit.SECONDS))
    
                .build();
    
        //定义请求实现
        Callable<Boolean> callable = new Callable<Boolean>() {
            int times = 1;
    
            @Override
            public Boolean call() throws Exception {
                log.info("call times={}", times);
                times++;
    
                if (times == 2) {
                    throw new NullPointerException();
                } else if (times == 3) {
                    throw new Exception();
                } else if (times == 4) {
                    throw new RuntimeException();
                } else if (times == 5) {
                    return false;
                } else {
                    return true;
                }
    
            }
        };
        //利用重试器调用请求
       return  retryer.call(callable);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    在这里插入图片描述
    具体相关质料可自行百度,因为比较简单这里就不啰嗦了

    spring-retry(spring)

    1.POM依赖

    <dependency>
      <groupId>org.springframework.retrygroupId>
      <artifactId>spring-retryartifactId>
     dependency>
    
    • 1
    • 2
    • 3
    • 4

    2.启用@Retryable

    @EnableRetry 
    @SpringBootApplication
    public class HelloApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(HelloApplication.class, args);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.演示

    @Service
    public class TestRetryServiceImpl implements TestRetryService {
    	
    	// 需要重试的方法  注意:  方法必须为 public
        @Override
        @Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
        public int test(int code,String mess,String name) throws Exception{
            System.out.println("test被调用,时间:"+ LocalTime.now());
            if (code==400){
                throw new Exception("情况不对头!");
            }
            System.out.println("test被调用,情况对头了!");
            return 200;
        }
    	// 回调方法  注意:  方法必须为 public
        @Recover
        public int recover(Exception e, int code,String name){
            System.out.println("回调方法执行!!!!");
            System.out.println("code: "+code);
            System.out.println("name: "+name);
            //记日志到数据库 或者调用其余的方法
            return 500;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    来简单解释一下 @Retryable注解中几个参数的含义:

    • value:抛出指定异常才会重试
    • include:和value一样,默认为空,当exclude也为空时,默认所有异常
    • exclude:指定不处理的异常
    • maxAttempts:最大重试次数,默认3次
    • backoff:重试等待策略,默认使用@Backoff,@Backoff的value默认为1000L,我们设置为2000L;multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为1.5,则第一次重试为2秒,第二次为3秒,第三次为4.5秒。

    当重试耗尽时还是失败,会出现什么情况呢?
    当重试耗尽时,RetryOperations可以将控制传递给另一个回调,即RecoveryCallback。Spring-Retry还提供了@Recover注解,用于@Retryable重试失败后处理方法。如果不需要回调方法,可以直接不写回调方法,那么实现的效果是,重试次数完了后,如果还是没成功没符合业务判断,就抛出异常。
    对于@Recover注解的方法,需要特别注意的是:

    • 方法的返回值必须与@Retryable方法一致
    • 方法的第一个参数,必须是Throwable类型的,与@Retryable配置的异常一致,其他参数位,需要哪个参数,写进去就可以了只要原方法有- 就行, 该回调方法与重试方法写在同一个实现类里面

    在这里插入图片描述

    点赞 -收藏-关注-便于以后复习和收到最新内容
    有其他问题在评论区讨论-或者私信我-收到会在第一时间回复
    在本博客学习的技术不得以任何方式直接或者间接的从事违反中华人民共和国法律,内容仅供学习、交流与参考
    免责声明:本文部分素材来源于网络,版权归原创者所有,如存在文章/图片/音视频等使用不当的情况,请随时私信联系我、以迅速采取适当措施,避免给双方造成不必要的经济损失。
    感谢,配合,希望我的努力对你有帮助^_^
  • 相关阅读:
    用循环结构程序自动化计算——计数循环
    Nginx配置使用详解
    keil5汇编实现1-100累加
    Actors 基于消息驱动的异步编程模型
    Hadoop
    LeetCode-剑指51-数组中的逆序对
    python办公自动化(九)os模块统计文件名、批量重命名、文件压缩
    Altium Designer,PCB处理最后GND以及铺铜经验
    【数据开发】DW数仓分层设计架构与同步策略(ODS、DWD、DWS等字段含义)
    【Azure K8S】AKS升级 Kubernetes version 失败问题的分析与解决
  • 原文地址:https://blog.csdn.net/weixin_45203607/article/details/126265780