详解如何在SpringBoot中优雅地重试调用第三方API

 更新时间:2022年12月16日 13:57:31   作者:JAVA旭阳  
作为后端程序员,我们的日常工作就是调用一些第三方服务,将数据存入数据库,返回信息给前端。本文为大家介绍了如何在SpringBoot中优雅地重试调用第三方API,需要的可以参考一下

前言

作为后端程序员,我们的日常工作就是调用一些第三方服务,将数据存入数据库,返回信息给前端。但你不能保证所有的事情一直都很顺利。像有些第三方API,偶尔会出现超时。此时,我们要重试几次,这取决于你的重试策略。

下面举一个我在日常开发中多次看到的例子:

public interface OutSource {
    List<Integer> getResult() throws TimeOutException;
}

@Service
public class OutSourceImpl implements OutSource {

    static Random random = new Random();
    @Override
    public List<Integer> getResult() {
        //mock failure
        if (random.nextInt(2) == 1)
            throw new TimeOutException();
        return List.of(1, 2, 3);
    }
}


@Slf4j
@Service
public class ManuallyRetryService {

    @Autowired
    private OutSource outSource;

    public List<Integer> getOutSourceResult(String data, int retryTimes) {
        log.info("trigger time:{}", retryTimes);

        if (retryTimes > 3) {
            return List.of();
        }

        try {
            List<Integer> lst = outSource.getResult();
            if (!CollectionUtils.isEmpty(lst)) {
                return lst;
            }

            log.error("getOutSourceResult error, data:{}", data);
        } catch (TimeOutException e) {
            log.error("getOutSourceResult timeout", e);
        }
        // 递归调用
        return getOutSourceResult(data, retryTimes + 1);
    }

}

@Slf4j
@RestController
public class RetryTestController {

    @Autowired
    private ManuallyRetryService manuallyRetryService;
    
    @GetMapping("manually")
    public String manuallyRetry() {
        List<Integer> result = manuallyRetryService.getOutSourceResult("haha", 0);
        if (!CollectionUtils.isEmpty(result)) {
            return "ok";
        }
        return "fail";
    }
}

看看上面这段代码,我认为它可以正常工作,当retryTimes达到4时,无论如何我们都会得到最终结果。但是你觉得写的好吗?优雅吗?下面我来介绍Spring中的一个组件:spring-retry,我们不妨来试一试。

Spring-Retry介绍使用

spring-retry是Spring中的提供的一个重试框架,提供了注解的方式,在不入侵原有业务逻辑代码的方式下,优雅的实现重处理功能。

安装依赖

如果你的是gradle应用,引入下面的依赖

implementation 'org.springframework.boot:spring-boot-starter-aop''org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.retry:spring-retry'

如果你的项目使用的是maven项目,引入下面的依赖

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

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

启用重试功能

添加@EnableRetry注解在入口的类上从而启用功能。

@SpringBootApplication
//看过来
@EnableRetry
public class TestSpringApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestSpringApplication.class, args);
    }

}

应用

我们以前面的为例,看看怎么使用,如下面的代码:

public interface OutSource {
    List<Integer> getResult() throws TimeOutException;
}

@Service
public class OutSourceImpl implements OutSource {

    static Random random = new Random();
    @Override
    public List<Integer> getResult() {
        //mock failure will throw an exception every time
        throw new TimeOutException();
    }
}

@Slf4j
@Service
public class RetryableService {

    @Autowired
    private OutSource outSource;

    // 看这里
    @Retryable(value = {TimeOutException.class}, maxAttempts = 3)
    public List<Integer> getOutSourceResult(String data) {
        log.info("trigger timestamp:{}", System.currentTimeMillis() / 1000);

        List<Integer> lst = outSource.getResult();
        if (!CollectionUtils.isEmpty(lst)) {
            return lst;
        }
        log.error("getOutSourceResult error, data:{}", data);

        return null;
    }

}


@Slf4j
@RestController
public class RetryTestController {

    @Autowired
    private RetryableService retryableService;

    @GetMapping("retryable")
    public String manuallyRetry2() {
        try {
            List<Integer> result = retryableService.getOutSourceResult("aaaa");
            if (!CollectionUtils.isEmpty(result)) {
                return "ok";
            }
        } catch (Exception e) {
            log.error("retryable final exception", e);
        }
        return "fail";
    }

}

关键在于Service层中的实现类中添加了 @Retryable注解,实现了重试, 指定value是TimeOutException异常会进行重试,最大重试maxAttempts3次。

验证

这一次,当我们访问http://localhost:8080/retryable时,我们将看到浏览器上的结果失败。然后在你的终端上看到:

INFO 66776 --- [nio-9997-exec-1] c.m.testspring.service.RetryableService  : trigger timestamp:1668236840
 INFO 66776 --- [nio-9997-exec-1] c.m.testspring.service.RetryableService  : trigger timestamp:1668236841
 INFO 66776 --- [nio-9997-exec-1] c.m.testspring.service.RetryableService  : trigger timestamp:1668236842
ERROR 66776 --- [nio-9997-exec-1] c.m.t.controller.RetryTestController     : retryable final exception

总结

本文分享了spring-retry重试框架最基础的使用,可以无侵入业务代码进行重试。关于spring-retry更多的使用建议可以自己去官网https://github.com/spring-projects/spring-retry 探索。

到此这篇关于详解如何在SpringBoot中优雅地重试调用第三方API的文章就介绍到这了,更多相关SpringBoot重试调用第三方API内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot如何配置文件properties和yml

    SpringBoot如何配置文件properties和yml

    这篇文章主要介绍了SpringBoot如何配置文件properties和yml问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Collections工具类_动力节点Java学院整理

    Collections工具类_动力节点Java学院整理

    Collections工具类提供了大量针对Collection/Map的操作。这篇文章主要介绍了Collections工具类_动力节点Java学院整理,需要的朋友可以参考下
    2017-04-04
  • 浅谈Java中File文件的创建以及读写

    浅谈Java中File文件的创建以及读写

    文中有非常详细的步骤介绍了Java中file文件的创建以及读写,对刚开始学习java的小伙伴们很有帮助,而且下文有非常详细的代码示例及注释哦,需要的朋友可以参考下
    2021-05-05
  • Java8使用Stream流实现List列表查询、统计、排序以及分组

    Java8使用Stream流实现List列表查询、统计、排序以及分组

    List的Stream流操作可以简化我们的代码,减少程序运行的压力,应对上面的问题,下面这篇文章主要给大家介绍了关于Java8使用Stream流实现List列表查询、统计、排序以及分组的相关资料,需要的朋友可以参考下
    2023-06-06
  • Java定时任务详解

    Java定时任务详解

    定时任务在项目中经常会使用到,本文主要根据博主自己使用定时的经验分如下几点介绍定时任务:1、Quartz定时任务简介及Spring配置Quartz定时任务;2、SchedulerFactory对定时任务进行增删改查
    2017-04-04
  • 使用IDEA将Java/Kotliin工程导出Jar包的正确姿势

    使用IDEA将Java/Kotliin工程导出Jar包的正确姿势

    这篇文章主要介绍了使用IDEA将Java/Kotliin工程导出Jar包的正确姿势,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 基于HTML5+js+Java实现单文件文件上传到服务器功能

    基于HTML5+js+Java实现单文件文件上传到服务器功能

    应公司要求,在HTML5页面上实现上传文件到服务器功能,对于我这样的菜鸟,真是把我难住了,最后还是请教大神搞定的,下面小编把例子分享到脚本之家平台,供大家参考
    2017-08-08
  • Java输出数组的3种方法

    Java输出数组的3种方法

    这篇文章主要给大家介绍了关于Java输出数组的3种方法,对于初学者来说,数组的输入输出是一个麻烦的问题,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • SpringBoot框架底层原理解析

    SpringBoot框架底层原理解析

    这篇文章主要介绍了SpringBoot底层原理,包括配置优先级的配置方式给大家讲解的非常详细,需要的朋友可以参考下
    2024-03-03
  • 浅谈使用Java Web获取客户端真实IP的方法示例详解

    浅谈使用Java Web获取客户端真实IP的方法示例详解

    这篇文章主要介绍了使用Java-Web获取客户端真实IP的方法示例详解。一般我们无法获取客户端真实IP,原因是:当我们通过request获取客户端IP时,自身服务器通常会为了保护信息或者负载均衡的目的,对自身服务器做反向代理。对此感兴趣可以了解一下
    2020-07-07

最新评论