spring-retry实现方法请求重试

简介: spring-retry实现方法请求重试

1 spring-retry是什么?

以往我们在进行网络请求的时候,需要考虑网络异常的情况,本文就介绍了利用spring-retry

是spring提供的一个重试框架,原本自己实现的重试机制,现在spring帮封装好提供更加好的编码体验。

2 使用步骤

2.1 引入maven库

代码如下(示例):

  <dependency>
      <groupId>org.springframework.retry</groupId>
      <artifactId>spring-retry</artifactId>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.3.9.RELEASE</version>
  </dependency>

2.2 在spring启动类上开启重试功能

提示:添加@EnableRetry注解开启
@SpringBootApplication
@EnableRetry
public class SpringRetryDemoApplication {
    public static SpringRetryAnnotationService springRetryAnnotationService;
    public static SpringRetryImperativeService springRetryImperativeService;
    public static TranditionalRetryService tranditionalRetryService;
    @Autowired
    public void setSpringRetryAnnotationService(SpringRetryAnnotationService springRetryAnnotationService) {
        SpringRetryDemoApplication.springRetryAnnotationService = springRetryAnnotationService;
    }
    @Autowired
    public void setSpringRetryImperativeService(SpringRetryImperativeService springRetryImperativeService) {
        SpringRetryDemoApplication.springRetryImperativeService = springRetryImperativeService;
    }
    @Autowired
    public void setTranditionalRetryService(TranditionalRetryService tranditionalRetryService) {
        SpringRetryDemoApplication.tranditionalRetryService = tranditionalRetryService;
    }
    public static void main(String[] args) {
        SpringApplication.run(SpringRetryDemoApplication.class, args);
        springRetryAnnotationService.test();
        springRetryImperativeService.test();
        tranditionalRetryService.test();
    }
}

2.2 公共业务代码

@Service
@Slf4j
public class CommonService {
    public void test(String before) {
        for (int i = 0; i < 10; i++) {
            if (i == 2) {
                log.error("{}:有异常哦,我再试多几次看下还有没异常", before);
                throw new RuntimeException();
            }
            log.info("{}:打印次数: {}", before, i + 1);
        }
    }
    public void recover(String before) {
        log.error("{}:还是有异常,程序有bug哦", before);
    }
}

2.3 传统的重试做法

@Service
@Slf4j
public class TranditionalRetryService {
    @Autowired
    CommonService commonService;
    public void test() {
        // 定义重试次数以及重试时间间隔
        int retryCount = 3;
        int retryTimeInterval = 3;
        for (int r = 0; r < retryCount; r++) {
            try {
                commonService.test("以前的做法");
            } catch (RuntimeException e) {
                if (r == retryCount - 1) {
                    commonService.recover("以前的做法");
                    return;
                }
                try {
                    Thread.sleep(retryTimeInterval * 1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
}

2.4 使用spring-retry的命令式编码

2.4.1 定义重试监听器

提示:监听重试过程的生命周期
@Slf4j
public class MyRetryListener extends RetryListenerSupport {
    @Override
    public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        log.info("监听到重试过程关闭了");
        log.info("=======================================================================");
    }
    @Override
    public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        log.info("监听到重试过程错误了");
    }
    @Override
    public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
        log.info("=======================================================================");
        log.info("监听到重试过程开启了");
        return true;
    }
}

2.4.2 定义重试配置

提示:配置RetryTemplate重试模板类
@Configuration
public class RetryConfig {
    @Bean
    public RetryTemplate retryTemplate() {
        // 定义简易重试策略,最大重试次数为3次,重试间隔为3s
        RetryTemplate retryTemplate = RetryTemplate.builder()
                .maxAttempts(3)
                .fixedBackoff(3000)
                .retryOn(RuntimeException.class)
                .build();
        retryTemplate.registerListener(new MyRetryListener());
        return retryTemplate;
    }
}

2.4.3 命令式编码

@Service
@Slf4j
public class SpringRetryImperativeService {
    @Autowired
    RetryTemplate retryTemplate;
    @Autowired
    CommonService commonService;
    public void test() {
        retryTemplate.execute(
                retry -> {
                    commonService.test("命令式");
                    return null;
                },
                recovery -> {
                    commonService.recover("命令式");
                    return null;
                }
        );
    }
}

2.5 使用spring-retry的注解式编码

@Service
@Slf4j
public class SpringRetryAnnotationService {
    @Autowired
    CommonService commonService;
    /**
     * 如果失败,定义重试3次,重试间隔为3s,指定恢复名称,指定监听器
     */
    @Retryable(value = RuntimeException.class, maxAttempts = 3, backoff = @Backoff(value = 3000L), recover = "testRecover", listeners = {"myRetryListener"})
    public void test() {
        commonService.test("注解式");
    }
    @Recover
    public void testRecover(RuntimeException runtimeException) {
        commonService.recover("注解式");
    }
}

3 SpringBoot整合spring-retry

我们使用SpringBoot来整合spring-retry组件实现重试机制。

3.1 添加@EnableRetry注解

在主启动类Application上添加@EnableRetry注解,实现对重试机制的支持

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

注意:@EnableRetry也可以使用在配置类、ServiceImpl类、方法上

3.2 接口实现

注意:接口类一定不能少,在接口类中定义你需要实现重试的方法,否则可能会无法实现重试功能

我的测试接口类如下:

public interface RetryService {    public String testRetry()  throws Exception;}

3.3 添加@Retryable注解

我们针对需要实现重试的方法上添加@Retryable注解,使该方法可以实现重试,这里我列出ServiceImpl中的一个方法:

@Service
public class RetryServiceImpl implements RetryService {
    @Override
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000,multiplier = 1.5))
    public String testRetry() throws Exception {
        System.out.println("开始执行代码:"+ LocalTime.now());
        int code = 0;
        // 模拟一直失败
        if(code == 0){
           // 这里可以使自定义异常,@Retryable中value需与其一致
            throw new Exception("代码执行异常");
        }
        System.out.println("代码执行成功");
        return "success";
    }
}

说明:@Retryable配置元数据情况:

value :针对指定抛出的异常类型,进行重试,这里指定的是Exception

maxAttempts :配置最大重试次数,这里配置为3次(包含第一次和最后一次)

delay: 第一次重试延迟间隔,这里配置的是2s

multiplier :每次重试时间间隔是前一次几倍,这里是1.5倍

3.4 Controller测试代码

@RestController
@RequestMapping("/test")
public class TestController {
    //  一定要注入接口,通过接口去调用方法
    @Autowired
    private RetryService retryService;
    @GetMapping("/retry")
    public String testRetry() throws Exception {
        return retryService.testRetry();
    }
}

3.5 发送请求

发送请求后,我们发现后台打印情况,确实重试了3次,并且在最后一次重试失败的情况下,才抛出异常,具体如下(可以注意下时间间隔)

3.6 补充:@Recover

一般情况下,我们重试最大设置的次数后,仍然失败抛出异常,我们会通过全局异常处理类进行统一处理,但是我们其实也可以自行处理,可以通过@Recover注解来实现,具体如下:

@Service
public class RetryServiceImpl implements RetryService {
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000,multiplier = 1.5))
    public String testRetry() throws Exception {
        System.out.println("开始执行代码:"+ LocalTime.now());
        int code = 0;
        if(code == 0){
            // 这里可以使自定义异常,@Retryable中value需与其一致
            throw new Exception("代码执行异常");
        }
        System.out.println("代码执行成功");
        return "success";
    }
    /**
     * 最终重试失败处理
     * @param e
     * @return
     */
    @Recover
    public String recover(Exception e){
        System.out.println("代码执行重试后依旧失败");
        return "fail";
    }
}

1)@Recover的方法中的参数异常类型需要与重试方法中一致

2)该方法的返回值类型与重试方法保持一致

再次测试如下(发现不会再抛出异常):

目录
相关文章
|
4天前
|
人工智能 JSON 前端开发
Spring Boot解决跨域问题方法汇总
Spring Boot解决跨域问题方法汇总
|
4天前
|
Java Spring 容器
解决Spring的UnsatisfiedDependencyException异常的方法
在Spring开发中,UnsatisfiedDependencyException异常意味着依赖注入失败,影响应用稳定性。该异常由Spring容器在无法满足bean依赖时抛出,常见原因包括bean定义错误、循环依赖、多个候选bean等。解决方法包括:检查bean定义和注入的正确性、解决循环依赖、确认依赖包的兼容性、使用@Qualifier或@Primary注解。通过日志、调试工具和异常对比来定位问题。持续学习Spring框架有助于更好地解决此类异常。
45 1
|
4天前
|
Java Spring
Spring的@Retryable实现方法重试
`@Retryable`注解用于配置异常重试,参数包括:指定异常类型`value`,额外包含异常`include`,排除异常`exclude`,最大尝试次数`maxAttempts`和回退策略`backoff`。可选地,可以用`retryExceptions`列表替换`value`。当重试失败,可使用`@Recover`注解定义恢复逻辑。
19 1
|
4天前
|
Java 应用服务中间件 微服务
Spring Boot可以同时处理多少请求?
Spring Boot的并发处理能力受硬件、JVM配置、嵌入式Tomcat的线程池(默认最大连接数8192,最大等待数100)、应用效率、系统架构和网络条件影响。开发阶段可能处理数百个并发,优化后在适合的硬件上可处理数千乃至上万并发。大型系统常结合负载均衡器。
23 2
|
4天前
|
Java 微服务 Spring
Spring Boot中获取配置参数的几种方法
Spring Boot中获取配置参数的几种方法
22 2
|
4天前
|
XML JSON Java
[AIGC] 在Spring Boot中指定请求体格式
[AIGC] 在Spring Boot中指定请求体格式
126 0
|
4天前
|
前端开发 Java Spring
请求映射掌握:探讨Spring MVC中@RequestMapping注解的妙用
请求映射掌握:探讨Spring MVC中@RequestMapping注解的妙用
24 1
请求映射掌握:探讨Spring MVC中@RequestMapping注解的妙用
|
4天前
|
Java Spring
spring cloud 通过feign请求动弹设置请求头heades
spring cloud 通过feign请求动弹设置请求头heades
29 0
|
4天前
|
JSON 前端开发 Java
【SpringBoot实战专题】「开发实战系列」全方位攻克你的技术盲区之Spring定义Jackson转换Null的方法和实现案例
【SpringBoot实战专题】「开发实战系列」全方位攻克你的技术盲区之Spring定义Jackson转换Null的方法和实现案例
46 0
|
4天前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
59 0