分享免费的编程资源和教程

网站首页 > 技术教程 正文

重试框架Spring retry实践 spring重试机制

goqiw 2024-09-25 20:12:56 技术教程 23 ℃ 0 评论

在分布式系统中,为了保证数据分布式事务的强一致性,大家在调用RPC接口或者发送MQ时,针对可能会出现网络抖动请求超时情况采取一下重试操作。大家用的最多的重试方式就是MQ了,但是如果你的项目中没有引入MQ,那就不方便了,本文主要介绍一下如何使用Spring Retry实现重试操作。

1. 添加maven依赖

[html] view plain

copy

1. <dependency> 
2. <groupId>org.springframework.retry</groupId> 
3. <artifactId>spring-retry</artifactId> 
4. <version>1.1.2.RELEASE</version> 
5. </dependency> 
6. <dependency> 
7. <groupId>org.aspectj</groupId> 
8. <artifactId>aspectjweaver</artifactId> 
9. <version>1.5.4</version> 
10. </dependency> 

2. 在启动里添加重试配置

[html] view plain

copy

1. @SpringBootApplication 
2. @EnableRetry 
3. public class Application { 
4. 
5. public static void main(String[] args) { 
6. SpringApplication.run(Application.class, args); 
7. } 
8. 
9. } 

3. 编写Service

[html] view plain

copy

1. @Service 
2. public class RemoteService { 
3. 
4. private static final Logger logger = LoggerFactory.getLogger(TestController.class); 
5. 
6. @Retryable(value= {BusinessException.class},maxAttempts = 3,backoff = @Backoff(delay = 5000l,multiplier = 2)) 
7. public void call() throws Exception { 
8. logger.info("do something..."); 
9. throw new BusinessException("RPC调用异常"); 
10. } 
11. @Recover 
12. public void recover(BusinessException e) { 
13. logger.info(" --------------------------- "); 
14. logger.info(e.getMessage()); 
15. } 
16. } 

4. 编写Controller

[html] view plain

copy

1. @RestController 
2. @RequestMapping("/test") 
3. public class TestController { 
4. 
5. private static final Logger logger = LoggerFactory.getLogger(TestController.class); 
6. 
7. @Autowired 
8. private RemoteService remoteService; 
9. 
10. @RequestMapping("/test") 
11. public String login() throws Exception { 
12. remoteService.call(); 
13. return String.valueOf("11"); 
14. } 

5. 访问http://localhost:8080/test/test

6. 测试日志

[html] view plain

copy

1. 2017-07-25 19:28:07 [INFO]-[http-nio-53602-exec-1]-[com.test.retry.service.RemoteService.call(RemoteService.java:19)] do something... 
2. 2017-07-25 19:28:12 [INFO]-[http-nio-53602-exec-1]-[com.test.retry.service.RemoteService.call(RemoteService.java:19)] do something... 
3. 2017-07-25 19:28:22 [INFO]-[http-nio-53602-exec-1]-[com.test.retry.service.RemoteService.call(RemoteService.java:19)] do something... 
4. 2017-07-25 19:28:22 [INFO]-[http-nio-53602-exec-1]-[com.test.retry.service.RemoteService.recover(RemoteService.java:24)] --------------------------- 
5. 2017-07-25 19:28:22 [INFO]-[http-nio-53602-exec-1]-[com.test.retry.service.RemoteService.recover(RemoteService.java:25)] RPC调用异常 

7. 相关配置说明

@EnableRetry能否重试。当proxyTargetClass属性为true时,使用CGLIB代理。默认使用标准JAVA注解。在spring Boot中此参数写在程序入口即可。

@Retryable 标注此注解的方法在发生异常时会进行重试

value:指定处理的异常类

include:指定处理的异常类和value一样,默认为空,当exclude也为空时,默认所有异常

exclude:指定异常不处理,默认空,当include也为空时,默认所有异常

maxAttempts:最大重试次数。默认3次

backoff:重试等待策略。默认使用@Backoff注解

@Backoff 重试等待策略

不设置参数时,默认使用FixedBackOffPolicy(指定等待时间),重试等待1000ms

设置delay,使用FixedBackOffPolicy(指定等待时间),重试等待填写的时间

设置delay和maxDealy时,重试等待在这两个值之间均态分布

设置delay、maxDealy、multiplier,使用 ExponentialBackOffPolicy(指数级重试间隔的实现),multiplier即指定延迟倍数,比如delay=5000l,multiplier=2,则第一次重试为5秒,第二次为10秒,第三次为20秒……

@Recover 用于@Retryable重试失败后处理方法,此注解注释的方法参数一定要是@Retryable抛出的异常,否则无法识别,可以在该方法中进行日志处理。

springboot 整合retry

加入依赖:

<dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.retry</groupId>
 <artifactId>spring-retry</artifactId>
 </dependency>
 <dependency>
 <groupId>org.aspectj</groupId>
 <artifactId>aspectjweaver</artifactId>
 </dependency></dependencies>

在主类上加上@EnableRetry注解,表示启用重试机制。

@SpringBootApplication@EnableRetrypublic class Application {
 public static void main(String[] args) {
 SpringApplication.run(Application.class,args);
 }
} 

定义一个简单的controller层:

@RestControllerpublic class HelloController {

Logger logger =LoggerFactory.getLogger(getClass());

@Autowired

private PayService payService;

@GetMapping("/createOrder")

public String createOrder(@RequestParamint num) throws Exception{

int remainingnum= payService.minGoodsnum(num == 0 ? 1: num);

logger.info("剩余的数量==="+remainingnum);

return "库库存成功";

}

}

在controller中调用减库存的service接口,

@Servicepublic class PayService {

private Logger logger =LoggerFactory.getLogger(getClass());

private final int totalNum = 100000;

@Retryable(value =Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier =1.5))

public int minGoodsnum(int num) throwsException{

logger.info("minGoodsnum开始"+ LocalTime.now());

if(num <= 0){

thrownew Exception("数量不对");

}

logger.info("minGoodsnum执行结束");

return totalNum- num;

}

}

在minGoodsnum方法上加上@Retryable注解,value值表示当哪些异常的时候触发重试,maxAttempts表示最大重试次数默认为3,delay表示重试的延迟时间,multiplier表示上一次延时时间是这一次的倍数。

重试三次抛出异常。

使用@Recover注解,当重试次数达到设置的次数的时候,还是失败抛出异常,执行的回调函数。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表