调用远程服务失败。
这些错误可能是因为网络波动造成的,等待过后重处理就能成功。通常来说,会用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@EnableRetrypublic 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 异常信息:===========出现异常了!===========
本文使用 文章同步助手 同步
在实际工作中,重处理是一个非常常见的场景,比如:
发送消息失败。
调用远程服务失败。