在实际工作中,重处理是一个非常常见的场景,比如:
- 发送消息失败。
- 调用远程服务失败。
这些错误可能是因为网络波动造成的,等待过后重处理就能成功。通常来说,会用try/catch,while循环之类的语法来进行重处理,但是这样的做法缺乏统一性,要多写很多重复代码。
public String doSth(String param) {
int count = 0;
String result = "";
while (count < 3) {
try {
result = retryRequestService.request(param);
break;
} catch (Exception e) {
count++;
}
}
return "响应是" + result;
}
spring-retry 可以通过注解,在不入侵原有业务逻辑代码的方式下,优雅的实现重处理功能。
spring-retry 是 Spring 全家桶中提供的开源重试框架,如果你用的是 Spring Boot 项目,那么接入起来会非常简单,只需要三步即可实现快速接入。
引入依赖
<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,让 Spring Boot 项目支持 spring-retry 的重试功能。
@SpringBootApplication
@EnableRetry
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
方法上添加 @Retryable
@Retryable(value = Exception.class, maxAttempts = 5, backoff = @Backoff(delay = 100))
public void retry(int code) throws Exception {
System.out.println("test被调用,时间:"+ LocalDateTime.now());
if (code == 0){
throw new Exception("===========出现异常了!===========");
}
System.out.println("方法执行结束=============");
}
@RequestMapping(value = "/test") public void test(int code) throws Exception { cityService.retry(code); }
> test被调用,时间:2022-12-06T10:56:20.081 test被调用,时间:2022-12-06T10:56:20.183 test被调用,时间:2022-12-06T10:56:20.293 test被调用,时间:2022-12-06T10:56:20.404 test被调用,时间:2022-12-06T10:56:20.521 2022-12-06 10:56:20.525 ERROR 16696 --- \[nio-8080-exec-1\] o.a.c.c.C.\[.\[.\[/\].\[dispatcherServlet\] : Servlet.service() for servlet \[dispatcherServlet\] in context with path \[\] threw exception \[Request processing failed; nested exception is java.lang.Exception: ===========出现异常了!===========\] with root cause
value:抛出指定异常才会重试 include:和value一样,默认为空,当exclude也为空时,默认所有异常 exclude:指定不处理的异常 maxAttempts:最大重试次数,默认3次 backoff:重试等待策略,默认使用@Backoff,@Backoff的value默认为1000(单位毫秒),我们设置为2000;multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为1.5,则第一次重试为2秒,第二次为3秒,第三次为4.5秒。
backoff = @Backoff(delay = 100) delay=100 意味着下一次的重试,要等 100 毫秒之后才能执行。
当重试耗尽时,RetryOperations可以将控制传递给另一个回调,即RecoveryCallback。Spring-Retry还提供了@Recover注解,用于@Retryable重试失败后处理方法。回调方法不是必要的。
@Recover public void recover(Exception e, int code){ System.out.println("回调方法执行!!!!"); System.out.println("retryParam参数值为:"+ code);
System.out.println("异常信息:"+e.getMessage());
}
回调方法的参数可以可选地包括抛出的异常和(可选)传递给原始可重试方法的参数。
* 方法的返回值必须与@Retryable方法一致
* 方法的第一个参数,必须是Throwable类型的,建议是与@Retryable配置的异常一致
* 回调方法与重试方法写在同一个类里面
> test被调用,时间:2022-12-06T11:37:39.272 test被调用,时间:2022-12-06T11:37:39.386 test被调用,时间:2022-12-06T11:37:39.497 test被调用,时间:2022-12-06T11:37:39.604 test被调用,时间:2022-12-06T11:37:39.712 回调方法执行!!!! retryParam参数值为:0 异常信息:===========出现异常了!===========
> 本文使用 [文章同步助手](https://juejin.cn/post/6940875049587097631) 同步