前言

作为后端程序员,我们的日常工作就是调用一些第三方服务,将数据存入数据库,返回信息给前端。但你不能保证所有的事情一直都很顺利。像有些第三方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 探索。

如果本文对你有帮助的话,请留下一个赞吧

欢迎关注个人公众号——JAVA旭阳

更多学习资料请移步:程序员成神之路

如何在SpringBoot中优雅地重试调用第三方API?的更多相关文章

  1. 如何在php中优雅的地调用python程序

    1.准备工作   安装有python和php环境的电脑一台. 2.书写程序. php程序如下 我们也可以将exec('python test.py') 换成 system('python test.p ...

  2. 【Chrome】如何在C++中增加给JavaScript调用的API

    本文示例说明了如何在Chrome浏览器中增加JavaScript API.为了简化,先假设是在已有的namespace中增加一个新的API,文章的最后将指出如果增加一下全新的namespace所需注意 ...

  3. 如何在MyBatis中优雅的使用枚举

    问题 在编码过程中,经常会遇到用某个数值来表示某种状态.类型或者阶段的情况,比如有这样一个枚举:   public enum ComputerState { OPEN(10), //开启 CLOSE( ...

  4. 如何在SpringBoot中使用JSP ?但强烈不推荐,果断改Themeleaf吧

    做WEB项目,一定都用过JSP这个大牌.Spring MVC里面也可以很方便的将JSP与一个View关联起来,使用还是非常方便的.当你从一个传统的Spring MVC项目转入一个Spring Boot ...

  5. 如何在 Swoole 中优雅的实现 MySQL 连接池

    如何在 Swoole 中优雅的实现 MySQL 连接池 一.为什么需要连接池 ? 数据库连接池指的是程序和数据库之间保持一定数量的连接不断开, 并且各个请求的连接可以相互复用, 减少重复连接数据库带来 ...

  6. 在Angular.js中的H5页面调用Web api时跨域问题处理

    /// <summary> /// 被请求时 /// 在Angular.js中的H5页面调用Web api时跨域问题处理 /// </summary> /// <para ...

  7. Java 代码中如何调用 第三方Api

    在代码中调用第三方API 获取数据 package com.example.demo.utils; import com.alibaba.fastjson.JSONObject; import lom ...

  8. vue 服务代理 调用第三方api

    项目中前期需要调用第三方API来获取汇率.因为直接调用会有跨域的问题,所以使用来服务代理. 在config配置代理可以这样写: 而调用接口就可以这样写: 坑:配置完成后一直报500,开始怀疑人生.最后 ...

  9. 你知道如何在springboot中使用redis吗

    特别说明:本文针对的是新版 spring boot 2.1.3,其 spring data 依赖为 spring-boot-starter-data-redis,且其默认连接池为 lettuce ​  ...

  10. spring-boot+mybatis开发实战:如何在spring-boot中使用myabtis持久层框架

    前言: 本项目基于maven构建,使用mybatis-spring-boot作为spring-boot项目的持久层框架 spring-boot中使用mybatis持久层框架与原spring项目使用方式 ...

随机推荐

  1. pgsql 的问题

    pgsql 怎么插入inet类型的数据?insert into table (remote_addr) values ( ?::INET); pgsql如何截取时间的精度 select  create ...

  2. Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution

    Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution 题目链接:https://atcoder.jp/contests/cf16- ...

  3. Xray

    Xray基础操作 代理设置 运行xray.exe xray.exe genca 运行后会生成ca.crt和cr.key 浏览器导入证书 设置代理7777端口 第一次启动 xray 之后,当前目录会生成 ...

  4. 前端开发日常——CSS动画无限轮播

    近来没有什么值得写的东西,空闲的时候帮前端的同学做了些大屏上的展示模块,就放在这里写写吧,手把手"需求->设计-> 实现",受众偏新手向. 为了直观便于理解, 直接把结 ...

  5. Linux基础_6_文本编辑

    vi i #编辑 ESC+:wq #保存退出 ESC+ZZ #保存退出 ESC+:q! #不保存退出 shift+z+q #不保存退出 dd #删除所在行 ESC+u #撤销dd误操作 :/字符串 # ...

  6. Vue中组件化编码使用(实战练习一)

    Vue中组件化编码的大致流程(初接触).组件之间的参数传递(最基础的形式).组件之间的配合完成一个需求 1.在Vue中进行组件化编码 1.1.组件化编码流程: (1).拆分静态组件:组件要按照功能点拆 ...

  7. SpringBoot→Maven项目快速搭建

    使用软件 :SpringToolSuite4 打开软件后在Package Explorer 栏中点击右键 Spring starter project 等待反应 填写完毕之后点击next     fi ...

  8. Linux的挖矿木马病毒清除(kswapd0进程)

    1.top查看资源使用情况 看到这些进程一直在变化,但是,主要是由于kswapd0进程在作怪,占据了99%以上的CUP,查找资料后,发现它就是挖矿进程 2.排查kswapd0进程 执行命令netsta ...

  9. Landau-Vishkin

    基础算法 假设我们有两个字符串:,每个字符串由A C G T四个字母组成. 在两个字符串上,都有三种可能的编辑操作(突变): 删除某个字符 在某个位置插入字符 改变某个字符 每一个编辑操作都有惩罚值. ...

  10. CSS line-break属性与中文标点换行

    关于标点符号把文字带着换行的问题解决方案 出现的问题 最近在弄一个介绍页面的时候遇到一个很巧的问题,在文本换行的时候刚好能够放下文字,但是标点符号把这个文字带着换行了 如下图所示: 如果的在上一行显示 ...