自定义注解结合AOP实现方法失败重试
明确需求
在开发中,在调用方法时会因为某些原因出现了预料中的异常,而在这些可控的异常时我们想要重新执行该方法。spring提供了实现重试机制的库Spring Retry,我们可以使用这个库优雅的调用重试。
那自己想要实现重试机制,该如何去实现呢;
下面是我使用AOP的AfterThrowing增强和自定义注解来实现简单的重试机制;
定义注解
重试注解接收3个参数:
- forException: 指定异常,当指定的异常抛出时,执行重试的逻辑
- fallback:当重试次数达最大时方法依然执行失败的回调
- maxRetryCount: 最大重试次数,默认值为3次
/**
* @author luyifo
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Retryable {
@Nonnull
Class<? extends Exception> forException();
@Nonnull
Class<? extends Fallback> fallback();
int maxRetryCount() default 3;
}
回调接口定义
这里简单定义了个回调的接口,实际开发中根据需求来定义fallback
/**
* @author luyifo
*/
public interface Fallback {
void exec(Object[] args);
}
回调接口实现
/**
* @author luyifo
*/
public class FallbackImpl implements Fallback{
@Override
public void exec(Object[] args) {
System.out.println("重试回调");
}
}
重试异常定义
自定义异常,在可以预料中的异常发生时进行抛出,后续在AOP中做判断来执行接下来的重试逻辑
/**
* @author luyifo
*/
public class RetryException extends Exception{
public RetryException(String message) {
super(message);
}
}
AOP核心
/**
* @author luyifo
*/
@Component
@Aspect
public class RetryAspect {
@Pointcut("@annotation(Retryable)")
public void pt() {}
@AfterThrowing(pointcut = "pt()", throwing = "ex")
public void after(JoinPoint jp, Exception ex) {
System.out.println("after");
MethodSignature signature = (MethodSignature) jp.getSignature();
Method method = signature.getMethod();
Retryable retryable = method.getAnnotation(Retryable.class);
// 异常判断,是否是重试注解指定的异常
if (ex.getClass() == retryable.forException()) {
int maxRetryCount = retryable.maxRetryCount();
int count = 0;
while (count < maxRetryCount) {
System.out.println("retry: " + count);
try {
method.invoke(jp.getTarget(), jp.getArgs());
// 当重试成功时直接返回
return;
} catch (Exception e) {
count++;
}
}
// 当重试次数达到最大值依然失败时执行回调
Class<? extends Fallback> fallback = retryable.fallback();
try {
Fallback instance = fallback.getDeclaredConstructor().newInstance();
Method exec = fallback.getMethod("exec", Object[].class);
exec.invoke(instance, new Object[]{jp.getArgs()});
} catch (Exception e) {
System.out.println("回调执行异常");
}
}
}
}
定义全局异常处理
/**
* @author luyifo
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> defaultExceptionHandle(Exception ex) {
return ResponseEntity
.badRequest()
.body(ex.getMessage());
}
}
测试
/**
* @author luyifo
*/
@RestController
public class RetryController {
@Retryable(forException = RetryException.class,fallback = FallbackImpl.class)
@GetMapping("/retry")
public void retry1() throws RetryException {
throw new RetryException("retry exception");
}
}
输出结果
after
retry: 0
retry: 1
retry: 2
重试回调
浙公网安备 33010602011771号