引入Maven依赖
<dependency>
<groupId>org.springframework.retrygroupId>
<artifactId>spring-retryartifactId>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
dependency>
使用@EnableRetry
注解开启重试机制
@SpringBootApplication
@EnableRetry
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
@Retryable说明
- recover:用于重试失败的兜底策略,一般不使用这个属性
- interceptor:忽略
- value:支持重试的异常,与include等价,如果value和include都不配置则重试所有
- include:需要重试的异常
- exclude:不重试的异常
- label:重试处的唯一名词定义,不定义则会基于方法签名生成,一般用不到
- stateful:是否有状态的重试(需要学习spring-retry 有状态重试相关,一般用不到)
- maxAttempts:最大执行次数
- maxAttemptsExpression:忽略
- backoff:重试策略
- listeners:spring-retry监听器配置,此处配置的是监听器在ioc容器中的id,需要了解spring retry的监听器才会使用
Backoff说明
- value:与delay效果等价,失败后等待多少ms重试下一次
- delay:与value效果等价,失败后等待多少ms重试下一次
- maxDelay:重试等待的最大时间,如果maxDelay
- multiplier:重试时间间隔指数增长倍数
- delayExpression:延时表达式
- maxDelayExpression:最大延时表达式
- multiplierExpression:增长表达式
- random:附加随机事件,需要multiplier>0
@Recover
一个方法如果需要recover策略,只需要在同类中加入一个方法,方法使用recover标记即可
注意:方法的第一个参数为异常类型,后面为原方法的参数
@Recover
public void defaultFallback(Exception e){
//do it
}
测试
注解:@Retryable
效果:默认重试3次,下次重试延时1s
2023-04-13 10:34:36.277 INFO 16704 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request 2...
2023-04-13 10:34:37.289 INFO 16704 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request 2...
2023-04-13 10:34:38.296 INFO 16704 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request 2...
注解:@Retryable(maxAttempts = 7,include = {Exception.class},backoff = @Backoff(delay = 1000,maxDelay = 10000))
效果:重试7次,延时在1000ms-10000ms之间
2023-04-13 10:36:38.484 INFO 6024 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request3 ...
2023-04-13 10:36:41.342 INFO 6024 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request3 ...
2023-04-13 10:36:44.318 INFO 6024 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request3 ...
2023-04-13 10:36:48.794 INFO 6024 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request3 ...
2023-04-13 10:36:50.264 INFO 6024 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request3 ...
2023-04-13 10:36:59.808 INFO 6024 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request3 ...
2023-04-13 10:37:01.882 INFO 6024 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request3 ...
注解:@Retryable(maxAttempts = 5,include = {Exception.class},backoff = @Backoff(delay = 1000,multiplier = 2))
效果:重试5次,第一次延时为1000ms,之后为第一次的2倍
2023-04-13 10:39:11.654 INFO 5692 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request4 ...
2023-04-13 10:39:12.665 INFO 5692 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request4 ...
2023-04-13 10:39:14.667 INFO 5692 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request4 ...
2023-04-13 10:39:18.672 INFO 5692 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request4 ...
2023-04-13 10:39:26.673 INFO 5692 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request4 ...
注解:@Retryable(maxAttempts = 5,backoff = @Backoff(value = 1500,maxDelay = 10000,multiplier = 3))
效果:最大重试5次,第一次延时1500ms,之后为前一次延时时长3倍,时长大于10000ms时,则按10000ms计算
2023-04-13 10:41:43.491 INFO 13928 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request5 ...
2023-04-13 10:41:45.005 INFO 13928 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request5 ...
2023-04-13 10:41:49.510 INFO 13928 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request5 ...
2023-04-13 10:41:59.523 INFO 13928 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request5 ...
2023-04-13 10:42:09.525 INFO 13928 --- [ main] c.v.service.impl.HttpRestServiceImpl : do request5 ...
失效场景
因为spring-retry采用的时aspectj动态代理,所以也会出现一些类似于spring事务的失效场景
例如
@Retryable
注解,那么在运行期间a方法调用b方法时相当于this.b(),而此时的this指向的是原本被代理的对象,所以会导致注解失效