Spring Retry 请求重试指南

在实际开发中, 例如在系统请求其他系统或资源的外部调用、操作时,由于网络故障等问题会造成短时间内失败。 我们希望当操作失败时,将使用重试策略来重试该操作。

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 请求重试指南

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址