基于 Guava Retry 在Spring封装一个重试功能

pom依赖

<dependency>
    <groupId>com.github.rholdergroupId>
    <artifactId>guava-retryingartifactId>
    <version>2.0.0version>
dependency>
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-aopartifactId>
dependency>

注解类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Retryable {
    /**
     * 需要重试的异常类型
     * this.isAssignableFrom(方法抛出的异常) 也就是说,方法抛出的异常必须是retryOn的子类或者子接口
     */
    Class<? extends Throwable> retryOn() default Throwable.class;

    // 重试次数
    int maxAttempts() default 3;

    // 重试间隔
    long delayMillis() default 1000;
}

import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
@Aspect
@Order(1)
public class RetryableAspect {

    @Around("@annotation(retryable)")
    public Object retry(ProceedingJoinPoint joinPoint, Retryable retryable) throws Throwable {
        Retryer<Object> retryer = RetryerBuilder.<Object>newBuilder()
                .retryIfExceptionOfType(retryable.retryOn())
                .withStopStrategy(StopStrategies.stopAfterAttempt(retryable.maxAttempts()))
                .withWaitStrategy(WaitStrategies.fixedWait(retryable.delayMillis(), TimeUnit.MILLISECONDS))
                .build();

        try {
            return retryer.call(() -> {
                try {
                    return joinPoint.proceed();
                } catch (Exception exception) {
                    throw exception;
                } catch (Throwable e) {
                    throw new WrapRetryThrowable(e);
                }
            });
        } catch (RetryException e) {
            throw e.getLastFailedAttempt().getExceptionCause();
        }
    }

    public static class WrapRetryThrowable extends Exception {

        public WrapRetryThrowable(Throwable cause) {
            super(cause);
        }
    }

}

测试类

在这里插入代码片@RestController
public class RetryController {

    /**
     * 顶级异常类测试
     * @return
     * @throws Throwable
     */
    @Retryable(
            retryOn = Exception.class,
            maxAttempts = 3,
            delayMillis = 1000
    )
    @GetMapping("/throwable")
    public String performTask() throws Throwable {
        System.out.println("performTask" + System.currentTimeMillis());
        // 在这里实现可能抛出异常的业务逻辑
        throw new Throwable("error");
    }


    /**
     * 异常类测试
     * @return
     * @throws CustomException
     */
    @Retryable(
            retryOn = CustomException.class,
            maxAttempts = 2,
            delayMillis = 1000
    )
    @GetMapping("/customException")
    public void customException() {
        System.out.println("customException" + System.currentTimeMillis());
        // 在这里实现可能抛出异常的业务逻辑
    }

    // 抛出的异常跟枚举异常不一致,不会重试
    @Retryable(
            retryOn = CustomException.class,
            maxAttempts = 3,
            delayMillis = 1000
    )
    @GetMapping("/customException2")
    public String customException2() throws Exception {
        System.out.println("customException2" + System.currentTimeMillis());
        // 在这里实现可能抛出异常的业务逻辑
        throw new Exception("这是一段自定义异常的抛出");
    }


}

你可能感兴趣的:(guava,spring,java)