背景:
在项目开发中,有时候会出现接口调用失败,本身调用又是异步的,如果是因为一些网络问题请求超时,总想可以重试几次把任务处理掉。
一些RPC框架,比如dubbo都是有重试机制的,但是并不是每一个项目多会使用dubbo框架,常规的小项目有时候直接使用http进行不同项目之间的交互。
个人想法:
使用spring aop和自定义注解来,建立一套重试机制。
根据切入点和自定义注解,来完成重试工作。
exps:
定义一个注解:
1 import org.springframework.stereotype.Component; 2 3 import java.lang.annotation.Documented; 4 import java.lang.annotation.ElementType; 5 import java.lang.annotation.Retention; 6 import java.lang.annotation.RetentionPolicy; 7 import java.lang.annotation.Target; 8 9 @Retention(RetentionPolicy.RUNTIME) 10 @Target(ElementType.METHOD) 11 @Documented 12 @Component 13 public @interface RetryProcess { 14 //重试的次数 15 int value() default 1; 16 }
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint; import org.springframework.stereotype.Component; import java.lang.reflect.Field; import java.util.concurrent.atomic.AtomicInteger; @Aspect @Component public class AspectExceptionInterceptor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @AfterThrowing(pointcut=("execution(* com.tom.plus.ctl..*(..)) && @annotation(com.tom.plus.compent.RetryProcess)")) public void tryAgain(JoinPoint point) { logger.info("------------开始重试------------"); try { Object object = point.getTarget(); Field field = object.getClass().getDeclaredField("threadLocal"); field.setAccessible(true); ThreadLocal<AtomicInteger> threadLocal = (ThreadLocal<AtomicInteger>) field.get(object); MethodSignature methodSignature = (MethodSignature) point.getSignature(); RetryProcess retryProcess = methodSignature.getMethod().getAnnotation(RetryProcess.class); if (threadLocal.get().intValue() < retryProcess.value()) { int index = threadLocal.get().incrementAndGet(); logger.info("开始重试第"+index); MethodInvocationProceedingJoinPoint methodPoint = ((MethodInvocationProceedingJoinPoint) point); methodPoint.proceed(); } } catch (Throwable throwable) { //logger.error("重试失败",throwable); tryAgain(point); } } }
测试代码:
@RetryProcess(value = 2)
@RequestMapping("/hero")
@ResponseBody
public String doIt2() {
//该接口会抛出异常,启动进行重试机制
testService.doProcess();
return "success";
}