重试机制:Spring-Retry的使用

学海无涯,旅“途”漫漫,“途”中小记,如有错误,敬请指出,在此拜谢!

在日常的开发中,有些场景,我们需要重试某个方法。比如当进行网络调用时,由于网络波动导致无法访问,需要重试几次。

一、github

https://github.com/spring-projects/spring-retry

二、使用方式

1、Spring-Boot

1.引入依赖

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

2.启动文件引入@EnableRetry标签,比如

@SpringBootApplication
@EnableWebMvc
@EnableScheduling
@EnableRetry//开启重试机制标签
public class MytestApplication {

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

}

3.需要重试的方法中,增加@Retryable标签,比如

    /**
     * 待重试的方法
     *
     * @param dto 重试传输dto
     * @author lin
     * @since 2019年9月24日
     * <p>
     * value:为指定重试的异常,只有该异常才会重试,如果多个异常重试,可以写做value = {RetryException.class,Exception.class}
     * maxAttempts: 为重试次数,默认为3次
     * @Backeoff中的标签
     * delay: 延迟时间(单位为毫秒,默认为0毫秒)
     * multiplier:延迟间隔倍率,比如如果定义延迟为1秒,延迟倍率为2,则第一次重试间隔1秒,第二次2秒,第三次4秒,依次类推
     * maxDelay:最大间隔时间
     */
    @Retryable(value = RetryException.class, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
    public void handle(RetryTransferDto dto) {
        log.info("正在处理消息,当前次数第{}次,消息为{}", dto.getCount(), dto.getMessage());
        if (true) { // 模拟失败
            dto.setCount(dto.getCount() + 1);
            dto.setMessage(dto.getMessage() + " haha ");
            throw new RetryException("消息处理失败,当前次数第" + dto.getCount() + "次,消息为" + dto.getMessage());
        }
    }

此处博主为了方便计数,增加了一个自定义的传输类RetryTransferDto,类的具体内容如下

import lombok.Data;

/**
 * 重试传输dto
 *
 * @author lin
 * @since 2019年9月24日
 */
@Data
public class RetryTransferDto {
    // 重试次数
    private int count = 0;
    // 重试内容
    private String message;
}

4.如果在最后一次重试报错后,想进入特定方法执行某些操作(比如写日志等),可以使用@Recover标签,例如

    /**
     * 重试达到指定次数时,进入此方法
     *
     * @author lin
     * @since 2019年9月24日
     */
    @Recover
    public void recover(RetryException e) {
        log.error("重试达到指定测试", e);
    }

5.日志输出如下所示

2019-09-24 10:49:28.572  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在处理消息,当前次数第1次,消息为haha
2019-09-24 10:49:29.575  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在处理消息,当前次数第2次,消息为haha haha 
2019-09-24 10:49:31.576  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在处理消息,当前次数第3次,消息为haha haha  haha 
2019-09-24 10:49:35.577  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在处理消息,当前次数第4次,消息为haha haha  haha  haha 
2019-09-24 10:49:43.577  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在处理消息,当前次数第5次,消息为haha haha  haha  haha  haha 
2019-09-24 10:49:43.582 ERROR 2416 --- [           main] com.lin.mytest.retry.RetryService        : 重试达到指定测试

org.springframework.retry.RetryException: 消息处理失败,当前次数第6次,消息为haha haha  haha  haha  haha  haha 
	at com.lin.mytest.retry.RetryService.handle(RetryService.java:33) ~[classes/:na]
	......

三、注意事项

1.因为Spring-Retry原理是切面操作,所以pom依赖中也需要有aop的依赖

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

2.因为是切面操作,所以待重试方法,不能是当前类中调用的方法。打个比方,A类中有方法a和方法b,方法a调用方法b时,在方法b上增加重试机制,此重试方法失效。
3.标签中maxAttempts、delay、multiplier等参数,需要是常量。如果想动态从yml或者properties的配置文件中获取,请使用对应的Expression参数。比如

    /**
     * 待重试的方法
     *
     * @param dto 重试传输dto
     * @author lin
     * @since 2019年9月24日
     * <p>
     * value:为指定重试的异常,只有该异常才会重试,如果多个异常重试,可以写做value = {RetryException.class,Exception.class}
     * maxAttemptsExpression: 为重试次数,默认为3次
     * Backeoff中的标签
     * delayExpression: 延迟时间(单位为毫秒,默认为0毫秒)
     * multiplierExpression:延迟间隔倍率,比如如果定义延迟为1秒,延迟倍率为2,则第一次重试间隔1秒,第二次2秒,第三次4秒,依次类推
     * maxDelayExpression:最大间隔时间
     */
    @Retryable(value = RetryException.class, maxAttemptsExpression = "${retry.attempts}", backoff = @Backoff(delayExpression = "${retry.delay}", multiplierExpression = "${retry.multiplier}"))
    public void handle(RetryTransferDto dto) {
        log.info("从配置文件获取参数,正在处理消息,当前次数第{}次,消息为{}", dto.getCount(), dto.getMessage());
        if (true) { // 模拟失败
            dto.setCount(dto.getCount() + 1);
            dto.setMessage(dto.getMessage() + " haha ");
            throw new RetryException("从配置文件获取参数,消息处理失败,当前次数第" + dto.getCount() + "次,消息为" + dto.getMessage());
        }
    }

四、我的测试代码

码云:

https://gitee.com/doubletreelin/mytest.git
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章