詳解如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API
前言
作為后端程序員,我們的日常工作就是調(diào)用一些第三方服務(wù),將數(shù)據(jù)存入數(shù)據(jù)庫,返回信息給前端。但你不能保證所有的事情一直都很順利。像有些第三方API,偶爾會出現(xiàn)超時。此時,我們要重試幾次,這取決于你的重試策略。
下面舉一個我在日常開發(fā)中多次看到的例子:
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);
}
// 遞歸調(diào)用
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";
}
}
看看上面這段代碼,我認(rèn)為它可以正常工作,當(dāng)retryTimes達(dá)到4時,無論如何我們都會得到最終結(jié)果。但是你覺得寫的好嗎?優(yōu)雅嗎?下面我來介紹Spring中的一個組件:spring-retry,我們不妨來試一試。
Spring-Retry介紹使用
spring-retry是Spring中的提供的一個重試框架,提供了注解的方式,在不入侵原有業(yè)務(wù)邏輯代碼的方式下,優(yōu)雅的實(shí)現(xiàn)重處理功能。
安裝依賴
如果你的是gradle應(yīng)用,引入下面的依賴
implementation 'org.springframework.boot:spring-boot-starter-aop''org.springframework.boot:spring-boot-starter-aop' implementation 'org.springframework.retry:spring-retry'
如果你的項(xiàng)目使用的是maven項(xiàng)目,引入下面的依賴
<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);
}
}
應(yīng)用
我們以前面的為例,看看怎么使用,如下面的代碼:
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";
}
}
關(guān)鍵在于Service層中的實(shí)現(xiàn)類中添加了 @Retryable注解,實(shí)現(xiàn)了重試, 指定value是TimeOutException異常會進(jìn)行重試,最大重試maxAttempts3次。
驗(yàn)證
這一次,當(dāng)我們訪問http://localhost:8080/retryable時,我們將看到瀏覽器上的結(jié)果失敗。然后在你的終端上看到:
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
總結(jié)
本文分享了spring-retry重試框架最基礎(chǔ)的使用,可以無侵入業(yè)務(wù)代碼進(jìn)行重試。關(guān)于spring-retry更多的使用建議可以自己去官網(wǎng)https://github.com/spring-projects/spring-retry 探索。
到此這篇關(guān)于詳解如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API的文章就介紹到這了,更多相關(guān)SpringBoot重試調(diào)用第三方API內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring-@Autowired注入與構(gòu)造函數(shù)注入使用方式
這篇文章主要介紹了spring-@Autowired注入與構(gòu)造函數(shù)注入使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12
SpringBoot啟動流程之引導(dǎo)上下文DefaultBootstrapContext的過程
本文詳細(xì)介紹了SpringBoot版本2.7.18中SpringApplication的run方法,引導(dǎo)注冊組件初始化器BootstrapRegistryInitializer是SpringBoot的第一個擴(kuò)展點(diǎn),負(fù)責(zé)應(yīng)用啟動早期階段的初始化和配置,感興趣的朋友跟隨小編一起看看吧2024-11-11
java書店系統(tǒng)畢業(yè)設(shè)計(jì) 總體設(shè)計(jì)(1)
這篇文章主要介紹了java書店系統(tǒng)畢業(yè)設(shè)計(jì),第一步系統(tǒng)總體設(shè)計(jì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10
通過jenkins發(fā)布java項(xiàng)目到目標(biāo)主機(jī)上的詳細(xì)步驟
這篇文章主要介紹了通過jenkins發(fā)布java項(xiàng)目到目標(biāo)主機(jī)上的詳細(xì)步驟,發(fā)布java項(xiàng)目的步驟很簡單,通過拉取代碼并打包,備份目標(biāo)服務(wù)器上已有的要發(fā)布項(xiàng)目,具體內(nèi)容詳情跟隨小編一起看看吧2021-10-10
使用Java進(jìn)行Json數(shù)據(jù)的解析(對象數(shù)組的相互嵌套)
下面小編就為大家?guī)硪黄褂肑ava進(jìn)行Json數(shù)據(jù)的解析(對象數(shù)組的相互嵌套)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08

