在实际开发中, 例如在系统请求其他系统或资源的外部调用、操作时,由于网络故障等问题会造成短时间内失败。 我们希望当操作失败时,将使用重试策略来重试该操作。
2 添加依赖
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> <version>1.1.5.RELEASE</version> </dependency> 复制代码
3 完整依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.devin</groupId> <artifactId>java-tutorial</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <!-- Web依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 重试依赖 --> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <!-- Aop依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> </dependencies> </project> 复制代码
4 开启重试
在启动类中添加 @EnableRetry
注解来启用全局重试。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.retry.annotation.EnableRetry; @SpringBootApplication @EnableRetry @Slf4j public class SpringRertyApplication { public static void main(String[] args) { SpringApplication.run(SpringRertyApplication.class, args); log.info("Spring Retry start ok!!!!") } } 复制代码
5 通过注解@Retryable实现重试
5.1 添加@Retryable注解
在需要重试的方法上添加 @Retryable
注解
@Retryable(
maxAttempts = 5,
backoff = @Backoff (delay = 1000L),
value = {
RuntimeException.class
}
)
public boolean retryMethod(String requestId) {
log.info("Processing request: {}", requestId);
throw new RuntimeException("Failed Request");
}
复制代码
示例中,仅当方法抛出 RuntimeException
时才尝试重试。 将最多进行 5
次重试,并延迟 1000
毫秒。
默认 @Retryable
不带任何属性,则该方法失败并发生异常,则重试最多3次,延迟一秒钟。
5.2 添加@Recover注解
如果所有重试结果均失败,那么最后抛出的异常将没有任何错误处理逻辑,我们可以使用注解 @Recover
来解决这个问题,例如:
@Recover public boolean retryMethod(RuntimeException ex, String requestId) { log.error("Recovering request {} - {}", requestId,ex.getMessage()); return false; } 复制代码
5.3 配置打印重试日志
application.properties
添加以下内容
logging.level.org.springframework.retry.support=debug
复制代码
5.4 测试
@Slf4j @Component public class RetryAnnotationTest implements ApplicationRunner { @Resource private RetryAnnotationService retryAnnotationService; @Override public void run(ApplicationArguments args) throws Exception { boolean result = retryAnnotationService.retryMethod(RandomUtil.randomNumbers(10)); log.info("result = {}",result); } } 复制代码
5.5 执行结果
2020-03-25 14:50:59.099 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Retry: count=0
2020-03-25 14:50:59.102 INFO [aop-spel,,,] 11212 --- [ main] c.s.s.r.a.RetryAnnotationService : Processing request: 4521824259
2020-03-25 14:51:00.104 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Checking for rethrow: count=1
2020-03-25 14:51:00.104 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Retry: count=1
2020-03-25 14:51:00.104 INFO [aop-spel,,,] 11212 --- [ main] c.s.s.r.a.RetryAnnotationService : Processing request: 4521824259
2020-03-25 14:51:01.104 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Checking for rethrow: count=2
2020-03-25 14:51:01.104 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Retry: count=2
2020-03-25 14:51:01.104 INFO [aop-spel,,,] 11212 --- [ main] c.s.s.r.a.RetryAnnotationService : Processing request: 4521824259
2020-03-25 14:51:02.106 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Checking for rethrow: count=3
2020-03-25 14:51:02.106 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Retry: count=3
2020-03-25 14:51:02.106 INFO [aop-spel,,,] 11212 --- [ main] c.s.s.r.a.RetryAnnotationService : Processing request: 4521824259
2020-03-25 14:51:03.106 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Checking for rethrow: count=4
2020-03-25 14:51:03.106 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Retry: count=4
2020-03-25 14:51:03.106 INFO [aop-spel,,,] 11212 --- [ main] c.s.s.r.a.RetryAnnotationService : Processing request: 4521824259
2020-03-25 14:51:03.106 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Checking for rethrow: count=5
2020-03-25 14:51:03.107 DEBUG [aop-spel,,,] 11212 --- [ main] o.s.retry.support.RetryTemplate : Retry failed last attempt: count=5
2020-03-25 14:51:03.107 ERROR [aop-spel,,,] 11212 --- [ main] c.s.s.r.a.RetryAnnotationService : Recovering request 4521824259 - Failed Request
复制代码
6 通过RetryTemplate实现重试
6.1 创建RetryTemplate配置
@Configuration
@ConditionalOnProperty(name = "retry.template.enable", havingValue = "true")
public class RetryConfig {
/**
* 多少毫秒以后重试
*/
@Value("${retry.template.backOff.period:5000}")
private Long backOffPeriod;
/**
* 重试次数
*/
@Value("${retry.template.max.attempts:3}")
private Integer maxAttempts;
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
//定义重试时间
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(backOffPeriod);
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
//定义重试次数
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(maxAttempts);
retryTemplate.setRetryPolicy(retryPolicy);
return retryTemplate;
}
}
复制代码
6.2 重试配置
application.properties
添加以下内容
retry.template.enable=true retry.template.backOff.period:300 retry.template.max.attempts:5 复制代码
6.3 使用RetryTemplate
@Slf4j
@Component
public class RetryTemplateTest implements ApplicationRunner {
@Resource
private RetryTemplate retryTemplate;
@Override
public void run(ApplicationArguments args) {
try {
boolean result = retryMethod(RandomUtil.randomNumbers(10));
log.info("Request Result={}", result);
} catch (RequestRetryException e) {
log.error("Request Exception - message:{}", e.getMessage());
}
}
private boolean retryMethod(String requestId) throws RequestRetryException {
return retryTemplate.execute(context -> {
log.info("Processing request - Param={} - Retry: count={}", requestId, context.getRetryCount());
//TODO 业务逻辑处理
throw new RequestRetryException("Request Retry");
}, context -> {
log.info("Recovering request - Param={} - Retry: count={}", requestId, context.getRetryCount());
//TODO 错误逻辑处理
return false;
});
}
}
复制代码
6.4 执行结果
2020-03-25 15:19:24.112 INFO [aop-spel,,,] 4120 --- [ main] c.s.s.r.template.RetryTemplateTest : Processing request - Param=5581499424 - Retry: count=0 2020-03-25 15:19:24.414 INFO [aop-spel,,,] 4120 --- [ main] c.s.s.r.template.RetryTemplateTest : Processing request - Param=5581499424 - Retry: count=1 2020-03-25 15:19:24.715 INFO [aop-spel,,,] 4120 --- [ main] c.s.s.r.template.RetryTemplateTest : Processing request - Param=5581499424 - Retry: count=2 2020-03-25 15:19:25.015 INFO [aop-spel,,,] 4120 --- [ main] c.s.s.r.template.RetryTemplateTest : Processing request - Param=5581499424 - Retry: count=3 2020-03-25 15:19:25.315 INFO [aop-spel,,,] 4120 --- [ main] c.s.s.r.template.RetryTemplateTest : Processing request - Param=5581499424 - Retry: count=4 2020-03-25 15:19:25.316 INFO [aop-spel,,,] 4120 --- [ main] c.s.s.r.template.RetryTemplateTest : Recovering request - Param=5581499424 - Retry: count=5 2020-03-25 15:19:25.316 INFO [aop-spel,,,] 4120 --- [ main] c.s.s.r.template.RetryTemplateTest : Request Result=false 复制代码
原文
https://juejin.im/post/5e7b0748e51d4526c932e0cc
本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Spring Retry 请求重试指南