guava-retrying 加入自定义注解,用aop方式使用

 

由于网络环境不太稳定,一些接口方法需要加入重试。正好看到Google's Guava library 项目https://github.com/rholder/guava-retrying,里面功能比较完善。但是官方没有提供注解方式使用,频繁使用会有点麻烦。所以查阅相关资料后编写了支持注解使用的方法

 定义注解类

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * des: guava retrying 注解使用
 * doc: https://github.com/rholder/guava-retrying
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retry {
    //指定异常时重试  由于pjp.proceed();需要try catch 异常,会有问题暂时没找到解决方法,先注释
//    Class[] exceptionClass() default {};

    //出现Exception时重试
    boolean retryIfException() default false;

    //程序出现RuntimeException异常时重试
    boolean retryIfRuntimeException() default false;

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

    //重试间隔 ms
    long waitStrategySleepTime() default 1000;

    //持续时间; 期间
    long duration() default 0;

    //返回值为指定字符串时重试
    String returnResult() default "willRertyString";

    //返回值为false时重试(默认关闭)  不支持同时设置指定返回字符串重试
    boolean closeReturnFalseRetry() default true;


}

 AOP类 

package net.capitalonline.retry.retryaspect;

import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicates;
import net.capitalonline.retry.Retry;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;


/**
* des: guava retrying 注解使用
* doc: https://github.com/rholder/guava-retrying
*/


@Aspect
@Component
public class RetryAspect {
@Pointcut("@annotation(net.capitalonline.retry.Retry)")
public void MethodCallConstraintPointcut(){
}

@Around(value = "@annotation(net.capitalonline.retry.Retry)")
public Object monitorAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("enter retry aspect");
Method method;
if (pjp.getSignature() instanceof MethodSignature) { //判断注解是否method 上
MethodSignature signature = (MethodSignature) pjp.getSignature();
method = signature.getMethod();
} else {
return null;
}
Retry annotation = method.getDeclaredAnnotation(Retry.class);
//重试时间,重试次数
if (annotation.duration() <= 0 && annotation.attemptNumber() <= 1) {
return pjp.proceed();
}

//不能设置开启returnFalse重试 和指定返回值重试
if(!annotation.closeReturnFalseRetry() && !annotation.returnResult().equals("willRertyString")){
return pjp.proceed();
}

RetryerBuilder builder = RetryerBuilder.newBuilder();

//重试次数
if (annotation.attemptNumber() > 0) {
builder.withStopStrategy(StopStrategies.stopAfterAttempt(annotation.attemptNumber()));
}
//退出策略
if (annotation.duration() > 0) {
builder.withStopStrategy(StopStrategies.stopAfterDelay(annotation.duration(), TimeUnit.MILLISECONDS));
}

//重试间间隔等待策略
if (annotation.waitStrategySleepTime() > 0) {
builder.withWaitStrategy(WaitStrategies.fixedWait(annotation.waitStrategySleepTime(), TimeUnit.MILLISECONDS));
}

// //停止重试的策略
// if (annotation.exceptionClass().length > 0) {
// for (Class retryThrowable : annotation.exceptionClass()) {
// if (retryThrowable != null && Throwable.class.isAssignableFrom(retryThrowable)) {
// builder.retryIfExceptionOfType(retryThrowable);
// }
// }
// }

//RuntimeException时重试
if (annotation.retryIfRuntimeException()){
builder.retryIfRuntimeException();

}
if (annotation.retryIfException()){
builder.retryIfException();
}
if (!annotation.returnResult().equals("willRertyString")){
builder.retryIfResult(Predicates.equalTo(annotation.returnResult()));
}

if (!annotation.closeReturnFalseRetry()){
builder.retryIfResult(Predicates.equalTo(annotation.closeReturnFalseRetry()));
}

return builder.build().call(() -> {
try {
System.out.println("aspect exec method "+ method.getName());
return pjp.proceed();
} catch (Throwable throwable) {
if (throwable instanceof Exception) {
throw (Exception) throwable;
} else {
throw new Exception(throwable);
}
}
});

// Callable<Object> callable=new Callable<Object>() {
// @Override
// public Object call() throws Exception {
// try {
// return pjp.proceed();
// }catch (Throwable e){
// e.printStackTrace();
// System.out.println("测试");
// return null;
// }
// }
// };
// try {
// return builder.build().call(callable);
// }catch (Exception e){
// System.out.println("重试");
// return "error";
// }
}
}

application.yaml 配置中加入

  aop:
    proxy-target-class: true

 

 使用实例


import org.springframework.stereotype.Component;

import java.lang.reflect.UndeclaredThrowableException;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class TestA {
int x=0;
@Retry(retryIfException = true, waitStrategySleepTime = 1200)
public void test() throws RemoteException{

try {
SimpleDateFormat sdf = new SimpleDateFormat();// 格式化时间
sdf.applyPattern("yyyy-MM-dd HH:mm:ss a");// a为am/pm的标记
Date date = new Date();// 获取当前时间
System.out.println("现在时间:" + sdf.format(date)); // 输出已经格式化的现在时间(24小时制)
int a=1/x;
System.out.println("1231");
} catch (Exception e) {
System.out.println("nonono");
throw new RemoteException("12321");
}
}
}

  

import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@WebAppConfiguration
@ContextConfiguration(classes = Application.class)
public class Tmpmytest {
    @Autowired
    TestA testA;
    @Test
    public void tmptest() {
        try {
            testA.test();
        } catch (Exception e) {
            System.out.println("ada");
        }


    }

}

  

 

posted @ 2021-11-22 15:35  skychi  阅读(398)  评论(0编辑  收藏  举报