接口调用失败重试方案

背景:
在项目开发中,有时候会出现接口调用失败,本身调用又是异步的,如果是因为一些网络问题请求超时,总想可以重试几次把任务处理掉。

一些RPC框架,比如dubbo都是有重试机制的,但是并不是每一个项目多会使用dubbo框架,常规的小项目有时候直接使用http进行不同项目之间的交互。

思路:
使用spring aop和自定义注解来,建立一套重试机制。

根据切入点和自定义注解,来完成重试工作。

定义一个自定义注解:

package com.it.ssm.annotation;

import org.springframework.stereotype.Component;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RetryProcess {
    //重试的次数
    int value() default 1;
}

定义一个切面:

package com.it.ssm.annotation;

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.util.concurrent.atomic.AtomicInteger;

@Aspect
@Component
public class AspectExceptionInterceptor {
    private  final Logger logger = LoggerFactory.getLogger(this.getClass());
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    @AfterThrowing(pointcut=("execution(* com.it.ssm..*(..)) && @annotation(com.it.ssm.annotation.RetryProcess)"))
    public void tryAgain(JoinPoint point) {
        try {
            Object object = point.getTarget();
            MethodSignature methodSignature = (MethodSignature) point.getSignature();
            RetryProcess retryProcess = methodSignature.getMethod().getAnnotation(RetryProcess.class);

            if (atomicInteger.intValue() < retryProcess.value()) {
                int i = atomicInteger.incrementAndGet();
               
               // 阻塞i秒后再进行重试,如果网络问题立即重试失败几率非常大所以建议阻塞一下再试
                Thread.sleep(1000 * i);
                
                logger.info("开始重试第" + i + "次");
                MethodInvocationProceedingJoinPoint methodPoint = ((MethodInvocationProceedingJoinPoint) point);
                // 再次调用方法
                methodPoint.proceed();
            }
        } catch (Throwable throwable) {
        	// 捕获到异常后再次重试
            tryAgain(point);
        }
    }
}

测试

@RetryProcess(value = 3)
@RequestMapping("/testException")
public void testException() throws Exception {
	// 这里为了方便测试手动抛一个异常,实际此处应该是调用接口逻辑
    throw new RuntimeException("测试重试异常");
}

控制台结果:

在这里插入图片描述

本文参考:http://www.cnblogs.com/tom-plus/p/7844228.html

猜你喜欢

转载自blog.csdn.net/qidasheng2012/article/details/85114116
今日推荐