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

简介: 如何在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更多的使用建议可以自己去官网github.com/spring-proj… 探索。

本文讲解了JDK中提供的两种生成随机数的方式,一个是JDK 1.0引入的Random类,另外一个是JDK1.7引入的ThreadLocalRandom类,由于底层的实现机制不同,ThreadLocalRandom的性能是远高于Random,建议后面大家在技术选型的时候优先使用ThreadLocalRandom

目录
相关文章
|
8天前
|
缓存 Java 应用服务中间件
随着微服务架构的兴起,Spring Boot凭借其快速开发和易部署的特点,成为构建RESTful API的首选框架
【9月更文挑战第6天】随着微服务架构的兴起,Spring Boot凭借其快速开发和易部署的特点,成为构建RESTful API的首选框架。Nginx作为高性能的HTTP反向代理服务器,常用于前端负载均衡,提升应用的可用性和响应速度。本文详细介绍如何通过合理配置实现Spring Boot与Nginx的高效协同工作,包括负载均衡策略、静态资源缓存、数据压缩传输及Spring Boot内部优化(如线程池配置、缓存策略等)。通过这些方法,开发者可以显著提升系统的整体性能,打造高性能、高可用的Web应用。
32 2
|
14天前
|
存储 消息中间件 前端开发
Web2py框架下的神秘力量:如何轻松集成第三方API,让你的应用不再孤单!
【8月更文挑战第31天】在开发现代Web应用时,常需集成第三方服务如支付网关、数据存储等。本文将指导你使用Web2py框架无缝接入第三方API。通过实例演示从注册获取API密钥、创建控制器、发送HTTP请求到处理响应的全过程。利用`requests`库与Web2py的内置功能,轻松实现API交互。文章详细介绍了如何编写RESTful控制器,处理API请求及响应,确保数据安全传输。通过本教程,你将学会如何高效整合第三方服务,拓展应用功能。欢迎留言交流心得与建议。
28 1
|
1月前
|
Java API 数据库
【神操作!】Spring Boot打造RESTful API:从零到英雄,只需这几步,让你的Web应用瞬间飞起来!
【8月更文挑战第12天】构建RESTful API是现代Web开发的关键技术之一。Spring Boot因其实现简便且功能强大而深受开发者喜爱。本文以在线图书管理系统为例,展示了如何利用Spring Boot快速构建RESTful API。从项目初始化、实体定义到业务逻辑处理和服务接口实现,一步步引导读者完成API的搭建。通过集成JPA进行数据库操作,以及使用控制器类暴露HTTP端点,最终实现了书籍信息的增删查改功能。此过程不仅高效直观,而且易于维护和扩展。
35 1
|
1月前
|
Java API 数据格式
Spring Boot API参数读取秘籍大公开!6大神器助你秒变参数处理大师,让你的代码飞起来!
【8月更文挑战第4天】Spring Boot凭借其便捷的开发和配置特性,成为构建微服务的热门选择。高效处理HTTP请求参数至关重要。本文介绍六种核心方法:查询参数利用`@RequestParam`;路径变量采用`@PathVariable`;请求体通过`@RequestBody`自动绑定;表单数据借助`@ModelAttribute`或`@RequestParam`;请求头使用`@RequestHeader`;Cookie则依靠`@CookieValue`。每种方法针对不同场景,灵活运用可提升应用性能与用户体验。
44 9
|
29天前
|
监控 安全 测试技术
确保第三方API安全的5个最佳实践
确保第三方API安全的5个最佳实践
|
2月前
|
JSON API 数据格式
App Inventor 2 天气预报App开发 - 第三方API接入的通用方法
通过调用第三方天气api,填入必要的参数,通过Web客户端请求url。返回json格式的数据结果,使用AppInventor2解析json结果,显示到App上即可。
105 5
|
2月前
|
开发框架 Java 测试技术
Spring Boot中的API文档生成
Spring Boot中的API文档生成
|
2月前
|
监控 安全 Java
在Java中集成第三方API调用的最佳实践
在Java中集成第三方API调用的最佳实践
|
2月前
|
安全 Java API
构建基于Spring Boot的REST API安全机制
构建基于Spring Boot的REST API安全机制
|
2月前
|
JSON 人工智能 API
App Inventor 2 人脸识别App开发 - 第三方API接入的通用方法
**App 效果图**:展示人脸识别功能,可识别性别和年龄。 **工作原理**:调用第三方人脸识别API,上传图片并接收返回的JSON数据,AppInventor2解析结果显示。
64 0