Java接口调用如何重试?GitHub Guava Retrying框架重试机制的使用
API远程接口在调用时会偶发网络超时、网络异常,导致调用失败,这时候某些特殊需求可能需要使用重试机制,当发生网络等异常时重新再发起调用请求。Github Retryer能完美的解决这一需求。
下面让我们看下如何使用Github Retryer。
1. 引入GitHub Retryer依赖
1 2 3 4 5 | < dependency > < groupId >com.github.rholder</ groupId > < artifactId >guava-retrying</ artifactId > < version >2.0.0</ version > </ dependency > |
jar包下载地址:https://maven.ityuan.com/maven2/com/github/rholder/guava-retrying/2.0.0
2. 根据调用返回接口判断是否需要重试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import com.github.rholder.retry.RetryException; import com.github.rholder.retry.Retryer; import com.github.rholder.retry.RetryerBuilder; import com.github.rholder.retry.StopStrategies; import com.github.rholder.retry.WaitStrategies; import com.google.common.base.Predicates; /** * @description: GitHub Retryer框架重试机制的使用 * @author ityuan.com * @date 2019年6月26日 上午11:07:38 */ public class RetryTester { public static void main(String[] args) throws ExecutionException, RetryException { Retryer<Long> retryer = RetryerBuilder.<Long>newBuilder() // 返回false也需要重试 .retryIfResult(Predicates.equalTo(1L)) // 重调策略 .withWaitStrategy(WaitStrategies.fixedWait( 1 , TimeUnit.SECONDS)) // 尝试次数 .withStopStrategy(StopStrategies.stopAfterAttempt( 3 )) .build(); retryer.call( new Callable<Long>() { @Override public Long call() throws Exception { System.out.println( "返回值是0L,看我能出现几次" ); return 1L; } } ); } } |
执行结果
1 2 3 4 5 6 | 返回值是0L,看我能出现几次 返回值是0L,看我能出现几次 返回值是0L,看我能出现几次 Exception in thread "main" com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 3 attempts. at com.github.rholder.retry.Retryer.call(Retryer.java:120) at com.test.RetryTester.main(RetryTester.java:31) |
3.根据调用发生异常判断是否需要重试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import com.github.rholder.retry.RetryException; import com.github.rholder.retry.Retryer; import com.github.rholder.retry.RetryerBuilder; import com.github.rholder.retry.StopStrategies; /** * @description: GitHub Retryer框架重试机制的使用 * @author ityuan.com * @date 2019年6月26日 上午11:07:38 */ public class RetryTester2 { public static void main(String[] args) throws ExecutionException, RetryException { Retryer<Long> retryer = RetryerBuilder.<Long>newBuilder() .retryIfException() .withStopStrategy(StopStrategies.stopAfterAttempt( 2 )) // 重试2次后停止 .build(); retryer.call( new Callable<Long>() { @Override public Long call() throws Exception { System.out.println( "异常打印,看我能出现几次" ); throw new RuntimeException(); } } ); } } |
执行结果
1 2 3 4 5 6 7 8 9 10 11 | 异常打印,看我能出现几次 异常打印,看我能出现几次 Exception in thread "main" com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 2 attempts. at com.github.rholder.retry.Retryer.call(Retryer.java:120) at com.test.RetryTester2.main(RetryTester2.java:24) Caused by: java.lang.RuntimeException at com.test.RetryTester2$1.call(RetryTester2.java:28) at com.test.RetryTester2$1.call(RetryTester2.java:1) at com.github.rholder.retry.AttemptTimeLimiters$NoAttemptTimeLimit.call(AttemptTimeLimiters.java:78) at com.github.rholder.retry.Retryer.call(Retryer.java:110) ... 1 more |
4.添加异常监听
1 | .withRetryListener( new MyRetryListener<>()) |
监听代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import com.github.rholder.retry.Attempt; import com.github.rholder.retry.RetryListener; import java.util.concurrent.ExecutionException; @SuppressWarnings ( "hiding" ) public class MyRetryListener<Long> implements RetryListener { @Override public <Long> void onRetry(Attempt<Long> attempt) { // 第几次重试,(注意:第一次重试其实是第一次调用) System.out.print( "[retry]time=" + attempt.getAttemptNumber()); // 距离第一次重试的延迟 System.out.print( ",delay=" + attempt.getDelaySinceFirstAttempt()); // 重试结果: 是异常终止, 还是正常返回 System.out.print( ",hasException=" + attempt.hasException()); System.out.print( ",hasResult=" + attempt.hasResult()); // 是什么原因导致异常 if (attempt.hasException()) { System.out.print( ",causeBy=" + attempt.getExceptionCause().toString()); } else { // 正常返回时的结果 System.out.print( ",result=" + attempt.getResult()); } // bad practice: 增加了额外的异常处理代码 try { Long result = attempt.get(); System.out.print( ",rude get=" + result); } catch (ExecutionException e) { System.err.println( "this attempt produce exception." + e.getCause().toString()); } System.out.println(); } } |
总结
RetryerBuilder是一个factory创建者,可以定制设置重试源且可以支持多个重试源,可以配置重试次数或重试超时时间,以及可以配置等待时间间隔,创建重试者Retryer实例。
RetryerBuilder的重试源支持Exception异常对象 和自定义断言对象,通过retryIfException 和retryIfResult设置,同时支持多个且能兼容。
retryIfException,抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。
retryIfRuntimeException只会在抛runtime异常的时候才重试,checked异常和error都不重试。
retryIfExceptionOfType允许我们只在发生特定异常的时候才重试,比如NullPointerException和IllegalStateException都属于runtime异常,也包括自定义的error
标签:
java
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库