Spring Retry 重试处理组件快速开始

springboot-retry

前言

在我们日常开发中,会遇到比如A服务调用B服务RPC超时、获取锁失败等场景,我们需要进行重试操作,为了不侵入代码优雅的进行重试,我们可以利用Spring提供的spring-retry组件来实现。

开始

  1. 引入依赖

核心依赖spring-retry,另外因为spring的retry底层是以AOP实现的,我们也需要引入aspectj

        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.5</version>
        </dependency>
  1. 开启@EnableRetry支持

@EnableRetry支持方法和类、接口、枚举级别的重试

@SpringBootApplication
@EnableRetry
public class SpringbootRetryApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootRetryApplication.class, args);
    }
}
  1. 编写重试service服务

@Retryable参数说明:

  • value:指定异常进行重试
  • maxAttempts:重试次数,默认3次
  • backoff:补偿策略
  • include:和value一样,默认空,当exclude也为空时,所有异常都重试
  • exclude:指定异常不重试,默认空,当include也为空时,所有异常都重试
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.remoting.RemoteTimeoutException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

/**
 * @author lb
 */
@Service
public class RetryService {

    private static final Logger LOGGER = LoggerFactory.getLogger(RetryService.class);

    @Retryable(
            // 指定发生的异常进行重试
            value = {RemoteAccessException.class, RemoteTimeoutException.class} ,
            // 重试次数
            maxAttempts = 3,
            // 补偿策略 delay:延迟多久执行补偿机制,multiplier:指定延迟的倍数,比如delay=5000,multiplier=2时,第一次重试为5秒后,第二次为10秒,第三次为20秒
            backoff = @Backoff(delay = 5000L,multiplier = 2)
    )
    public String call(){
        LOGGER.info("执行重试方法.....");
//        throw new RemoteAccessException("RPC访问异常");
        throw new RemoteTimeoutException("RPC调用超时异常");
    }

    @Recover
    public String recover(RemoteAccessException e){
        LOGGER.info("最终重试失败,执行RemoteAccess补偿机制 error : {}",e.getMessage());
        return "ok";
    }

    @Recover
    public String recover(RemoteTimeoutException e){
        LOGGER.info("最终重试失败,执行RemoteTimeout补偿机制 error : {}",e.getMessage());
        return "ok";
    }

}

有几点需要注意的地方:

  • 重试机制的service服务必须单独创建一个class,不能写在接口的实现类里,否则会抛出ex
  • @Retryable是以AOP实现的,所以如果@Retryable标记的方法被其他方法调用了,则不会进行重试。
  • recover方法的返回值类型必须和call()方法的返回值类型一致

测试

  • 编写测试类
import com.lb.springboot.retry.service.RetryService;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SpringbootRetryApplicationTests {

    @Autowired
    private RetryService retryService;

    @Test
    public void testRetry(){
        String result = retryService.call();
        MatcherAssert.assertThat(result, Matchers.is("ok"));
    }

}
  • 执行结果:
 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.4.RELEASE)

2020-12-17 14:15:58.083  INFO 71362 --- [           main] c.l.s.r.SpringbootRetryApplicationTests  : Starting SpringbootRetryApplicationTests on yunnashengdeMacBook-Pro.local with PID 71362 (started by yunnasheng in /Users/yunnasheng/work/github-workspace/springboot-retry)
2020-12-17 14:15:58.086  INFO 71362 --- [           main] c.l.s.r.SpringbootRetryApplicationTests  : No active profile set, falling back to default profiles: default
2020-12-17 14:15:59.238  INFO 71362 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-12-17 14:15:59.470  INFO 71362 --- [           main] c.l.s.r.SpringbootRetryApplicationTests  : Started SpringbootRetryApplicationTests in 1.686 seconds (JVM running for 2.582)

2020-12-17 14:15:59.668  INFO 71362 --- [           main] c.l.s.retry.service.RetryService         : 执行重试方法.....
2020-12-17 14:16:04.674  INFO 71362 --- [           main] c.l.s.retry.service.RetryService         : 执行重试方法.....
2020-12-17 14:16:14.675  INFO 71362 --- [           main] c.l.s.retry.service.RetryService         : 执行重试方法.....
2020-12-17 14:16:14.676  INFO 71362 --- [           main] c.l.s.retry.service.RetryService         : 最终重试失败,执行RemoteTimeout补偿机制 error : RPC调用超时异常

源代码: https://gitee.com/yunnasheng/springboot-retry.git

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