在SpringBoot项目的开发中,我们会有一种场景,就是调用接口或方法失败后需要进行重试。此时我们可以使用Spring-retry框架进行方法重试。
引入依赖
org.springframework.retry
spring-retry
开启重试功能
在SpringBoot项目的主启动类上添加@EnableRetry注解。
使用方式
在接口或是方法上添加@Retryable注解表示当前方法如果出现异常需要进行重试。
@Retryable注解中的属性
value:指定异常类型,只有抛出了此异常才会进行重试。
include:与value作用相同。
exclude:指定哪些异常不需要处理。
maxAttempts:最大重试次数。
backoff:重试等待策略,这个属性比较特殊,他的值是@Backoff注解,我们根据这个注解的参数去配置等待策略。
-----------------------------------------------------------------------------------------------------------------------
@Backoff注解属性
value:延迟属性,单位是毫秒,默认1秒钟重试一次。
multiplier:延迟倍数,通过value属性与此属性相乘获取第一次的重试时间,重试后再次乘以此参数获取下一次的重试时间。
如果重试失败不想继续重试了,我们可以通过@Recover注解创建一个重试失败的处理方法。
我们使用此框架一定要注意以下几点,否则直接上生产就报错给你看!
1. 回调方法必须与重试方法在同一个类中。
2. 多个回调方法返回值不能相同,也就是说同一个类中不能有两个String类型的回调方法,否则调用回调方法时会报异常。
3. 回调方法可以添加异常参数,表示我们捕获到的异常,也可以选择无参。
4. 回调方法最后的返回值会直接作为重试方法的返回值。
5. 捕获的异常相当于被try...catch...了,回调方法就是其中catch那部分(这个意思就是说异常信息需要自己处理,不会直接打印了)。
其实retry框架也有很多局限性,比如他只支持对于异常的捕获,并且重试失败之后调用回调方法只能传递异常信息,无法传递其他信息。
相比于retry框架,Guava-Retry框架则更加灵活。
引入依赖
com.github.rholder
guava-retrying
2.0.0
使用方式
这个框架大部分常用的内容都在这个类里面了。
package com.project.springtest.controller;
import com.github.rholder.retry.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("api/exam")
public class ExamController {
@Autowired
private MyService myService;
// 注入应用上下文,是为了通过IOC容器去获取当前类的Bean对象
@Autowired
private ApplicationContext applicationContext;
// 声明一个重试者对象(泛型的声明一般使用要重试的方法返回值)
public static Retryer retryer;
static {
// 创建一个重试者对象,进行重试策略配置
retryer = RetryerBuilder. newBuilder() // 此处泛型与声明的重试者对象泛型一致
.retryIfExceptionOfType(ClassNotFoundException.class) // 对指定异常进行重试
.retryIfException() // 对所有异常进行重试
.retryIfResult(res-> res == 1) // 设置根据结果,如果相比结果为true则进行重试(lambda表达式res类型与newBuilder前的泛型一致)
.retryIfRuntimeException() // 对所有运行时异常进行重试
.withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS)) // 设置重试等待间隔时间
.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 设置最大重试次数
.build();
}
@GetMapping("/exam1")
public String initiateApproveProcess() {
System.out.println("执行了此方法");
try {
// 此方法直接调用我们需要重试的方法,可以接收返回值
// 由于我们调用的是本类的方法,但并不想去新创建对象,所以我们在IOC容器中去获取Bean对象
// 通过BeanName去获取Bean,名字默认首字母小写
Integer result = ExamController.retryer.call(() -> ((ExamController) applicationContext.getBean("examController")).test());
} catch (IllegalArgumentException | RetryException | ExecutionException e) {
// 如果重试达到最大次数还没有成功返回则会抛出RetryException异常,我们可以将其捕获并进行处理
System.out.println(e.getMessage());
}
return "OK";
}
/**
* 需要重试的方法
* @return 返回数字
*/
public Integer test() {
System.out.println("重试");
return 23;
}
}
SpringBoot中的重试框架就到这里了,在工作中可以根据具体情况进行选择。希望能够对小伙伴们有帮助。