侧边栏壁纸
博主头像
银河小徐博主等级

A Good Boy ⛵️⛵️⛵️

  • 累计撰写 42 篇文章
  • 累计创建 38 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Spring-Retry 重试机制

银河小徐
2022-04-26 / 0 评论 / 0 点赞 / 58 阅读 / 3,230 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-06-04,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

背景

在实际工作过程中,因网络波动、服务并发限制等原因造成接口服务调用失败,MQ中间件发送消息失败等,可以采取重试手段,重试机制是常见的一种处理问题的手段。

重试的手段有很多种,比如我们自己用代码逻辑实现,但是这种方式对代码的侵入性太强,不够优雅。

今天我给大家带来一种更优雅的方式实现重试机制,那就是 spring-retry 框架,该框架利用了 AOP 的特性,只需引入注解就可以轻松实现重试次数、重试延迟时间、重试触发条件、重试的回调方法等等。

使用

添加依赖

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

启动类增加 @EnableRetry 注解

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

重试接口

/**
 * @author xiaoxuxuy
 * @date 2022/4/26 3:18 下午
 */
public interface TestRetryService {

    /**
     * 测试重试
     *
     * @param code
     * @return
     * @throws Exception
     */
    int testRetry(int code) throws Exception;

}

重试接口实现

import com.scaffolding.example.sys.service.TestRetryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
 * @author xiaoxuxuy
 * @date 2022/4/26 3:37 下午
 */
@Slf4j
@Service
public class TestRetryServiceImpl implements TestRetryService {

    /**
     * @param code
     * @return
     * @throws Exception
     */
    @Override
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public int testRetry(int code) throws Exception {
        log.info("testRetry, 时间: {}", LocalDateTime.now());
        if (code == 0) {
            throw new Exception("请求参数为0,出现异常");
        }
        System.out.println("testRetry调用成功!");
        return 200;
    }

    @Recover
    public int recover(Exception e, int code) {
        System.out.println("重试次数结束后还有异常,回调方法开始执行!");
        // 记录日志到数据库或者调用其余的方法
        return 400;
    }

}

注解释意:

@EnableRetry:此注解用于开启重试框架,可以修饰在SpringBoot启动类上面,也可以修饰在需要重试的类上
   proxyTargetClass:Boolean类型,用于指明代理方式【true:cglib代理,false:jdk动态代理】默认使用jdk动态代理
@Retryable
   value:Class[]类型,用于指定需要重试的异常类型
   include:Class[]类型,作用同value类似
   exclude:Class[]类型,指定不需要重试的异常类型
   maxAttemps:int类型,指定最多重试次数,默认3
   backoff:Backoff类型,指明补偿机制
   @BackOff
      delay:指定延迟后重试,默认为1000L,即1s后开始重试 ;
      multiplier:指定延迟的倍数
@Recover
   当重试次数耗尽依然出现异常时,执行此异常对应的@Recover方法。
   异常类型需要与Recover方法参数类型保持一致,
   recover方法返回值需要与重试方法返回值保证一致

测试

import com.scaffolding.example.sys.service.TestRetryService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ExampleApplicationTest {

    @Autowired
    private TestRetryService retryService;

    @Test
    public void test() throws Exception {
        retryService.testRetry(0);
    }

}

运行结果:

2022-04-26 17:32:41.890  INFO c.s.e.s.s.impl.TestRetryServiceImpl     [28][main] testRetry, 时间: 2022-04-26T17:32:41.889
2022-04-26 17:32:43.895  INFO c.s.e.s.s.impl.TestRetryServiceImpl     [28][main] testRetry, 时间: 2022-04-26T17:32:43.895
2022-04-26 17:32:46.900  INFO c.s.e.s.s.impl.TestRetryServiceImpl     [28][main] testRetry, 时间: 2022-04-26T17:32:46.900
重试次数结束后还有异常,回调方法开始执行!

注意 ⚠️

retry 重试机制无效:因为 retry 用到啦 aspect 增强,所以如果在同一类方法中内部调用,会使 aspect 增强实效,自然 retry 也随之实效。

代码如下:

public class Test {
    public void A() {
        B();
    }
 
    @Retryable(Exception.class)
    public void B() {
        throw new RuntimeException("retry...");
    }
}
0

评论区