如何在java中使用AspectJ实现重试机制?

问题描述 投票:1回答:1

我正在尝试使用 AspectJ. 如果一个方法抛出任何异常 AspectJ 应该再次调用方法。

这是我的代码。

重试注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Retry {
    int retryCount();
}

重试方面:

@Aspect
public class RetryAspect {
    @Around("@annotation(main.Retry)")
    public Object profile(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object response = null;
        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
        Retry annotation = method.getAnnotation(Retry.class);
        int retryCount = annotation.retryCount();
        boolean successfull = false;
        do{
            try {
                response = proceedingJoinPoint.proceed();
                successfull = true;
            }catch(Exception ex){
                retryCount--;
                if(retryCount < 0){
                    throw ex;
                }
            }
        }while(!successfull);
        return response;
    }
}

main method:

public class Main {

    @Retry(retryCount = 1)
    public int method1() throws Exception  {
        System.out.println("method 1");
        throw new Exception();
    }

    public static void main(String[] args) throws Exception {
        Main m = new Main();
        boolean successfull = false;
        m.method1();
        System.out.println("Exit main");
    }
}

如果我的理解是正确的,程序应该打印 "方法1 "两次并抛出异常,但 "方法1 "被打印了4次,这是输出。

method 1
method 1
method 1
method 1
Exception in thread "main" java.lang.Exception
    at main.Main.method1_aroundBody0(Main.java:8)
    at main.Main.method1_aroundBody1$advice(Main.java:24)
    at main.Main.method1(Main.java:1)
    at main.Main.method1_aroundBody2(Main.java:14)
    at main.Main.method1_aroundBody3$advice(Main.java:24)
    at main.Main.main(Main.java:14)

如果我的实现有什么问题,请指出。

java java-8 aspectj
1个回答
1
投票

你使用的是AspectJ,而不是Spring AOP,这也是为什么你的pointcut同时符合以下两个条件

  • call() (方法调用的来源)和
  • execution() (目标方法本身)

joinpoints,因此你看到的是4个而不是2个日志输出。如果你能养成一个习惯,至少在开发过程中,总是在建议的开头打印完整的joinpoint(而不仅仅是签名或joinpoint的另一小部分),你自己很容易发现。你可以在后面注释出来。所以你可以直接添加

System.out.println(proceedingJoinPoint);

你就会明白我的意思。

解决这个问题的最简单的方法是将pointcut限制为调用或执行。如果你可以选择的话,我建议选择后者,因为只编织一个方法而不是100个调用者更好。你要把你的pointcut修改为(未经测试,我在路上写的是 "免提")。

@Around("@annotation(main.Retry) && execution(* *(..))")
© www.soinside.com 2019 - 2024. All rights reserved.