详解如何在SpringBoot中优雅地重试调用第三方API
作者:JAVA旭阳
前言
作为后端程序员,我们的日常工作就是调用一些第三方服务,将数据存入数据库,返回信息给前端。但你不能保证所有的事情一直都很顺利。像有些第三方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
异常会进行重试,最大重试maxAttempts
3次。
验证
这一次,当我们访问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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!