Springboot 整合Retry 实现重试机制

重试,在项目需求中是非常常见的,例如遇到网络波动等,要求某个接口或者是方法可以最多/最少调用几次;
实现重试机制,非得用Retry这个重试框架吗?那肯定不是,相信很多伙伴手写一下控制流程的逻辑也可以达到重试的目的。

那么用Retry的好处是什么? 简单来说,就是优雅。

Retry重试框架,支持AOP切入的方式使用,而且能使用注解;想想,重试次数、重试延迟、重试触发条件、重试的回调方法等等我们都能很轻松结合注解以一种类似配置参数的方式去实现,优雅无疑。

那么,我们接下来就来一起使用Springboot整合这个Retry重试框架:

1、pom.xml需要引入的jar包:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 重试机制 -->
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.2.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

2、创建一个测试的重试类

需要重试的方法上加上@Retryable注解,注解参数的含义如下:

  1. value:抛出指定异常才会重试
  2. include:和value一样,默认为空,当exclude也为空时,默认所有异常
  3. exclude:指定不处理的异常
  4. maxAttempts:最大重试次数,默认3次
  5. backoff:重试等待策略,默认使用@Backoff,@Backoff的value默认为1000L,我们设置为2000L;multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为1.5,则第一次重试为2秒,第二次为3秒,第三次为4.5秒。
    当重试耗尽时还是失败,会出现什么情况呢?

当重试耗尽时,RetryOperations可以将控制传递给另一个回调,即RecoveryCallback。Spring-Retry还提供了@Recover注解,用于@Retryable重试失败后处理方法。如果不需要回调方法,可以直接不写回调方法,那么实现的效果是,重试次数完了后,如果还是没成功没符合业务判断,就抛出异常。

可以看到传参里面写的是 Exception e,这个是作为回调的接头暗号(重试次数用完了,还是失败,我们抛出这个Exception e通知触发这个回调方法)。对于@Recover注解的方法,需要特别注意的是:

  1. recover方法的返回值必须与@Retryable方法一致
  2. 方法的第一个参数,必须是Throwable类型的,建议是与@Retryable配置的异常一致,其他的参数,需要哪个参数,写进去就可以了(@Recover方法中有的)
  3. 该回调方法与重试方法写在同一个实现类里面
package com.example.demo;

import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

/**
 * @description: TODO
 * @author: 80005590 luxing
 * @date: 2021/5/8 14:46
 */
@Service
public class RetryServiceImpl implements RetyrService{

    @Override
    @Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
    public String testRetry(int code)throws Exception {
        System.out.println("开始执行业务方法==========");
        System.out.println("结束执行业务方法==========");
        if(code == 0){
            throw new Exception("请求返回错误");
        }
        return "请求成功";
    }

    @Recover
    public String recover(Exception e){
        System.out.println("回调方法执行!!!!");
        //记日志到数据库 或者调用其余的方法
        return "回调方法返回:" + e.getMessage();
    }
}

3、写一个测试方法

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @description: TODO
 * @author: 80005590 luxing
 * @date: 2021/5/8 14:54
 */

@RestController
public class TestController {

    @Autowired
    RetyrService retyrService;

    @GetMapping("/testRetry")
    public String testRetry() throws Exception {
        int code=0;

        String result = retyrService.testRetry(code);
        return result;
    }
}

4、在启动类中加上@EnableRetry注解,引入重试相关功能(不加不会使用重试)

@SpringBootApplication
@EnableRetry
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

5、启动后测试结果如下

我们这个测试模拟的场景是,传值code,一直是0;然后业务方法判断如果是0,代表业务不通,失败(网络波动了或者是等等),然后就是触发重试,最后如果重试几次都不成功,然后调用回调方法(可以进行日志记录或者调用其他业务方法等等)。
Springboot 整合Retry 实现重试机制_第1张图片
Springboot 整合Retry 实现重试机制_第2张图片

6、总结:

  1. 由于是基于AOP实现,所以不支持类里自调用方法
  2. 方法内不能使用try catch,只能往外抛异常
  3. recover重试回调每个类只能有一个
  4. @Recover注解来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中),此注解注释的方法参数一定要是@Retryable抛出的异常,否则无法识别,可以在该方法中进行日志处理。

你可能感兴趣的:(spring,boot,/spring,cloud,spring,boot,java)