Как реализовать механизм Retry в java с помощью AspectJ - PullRequest
1 голос
/ 17 июня 2020

Я пытаюсь реализовать механизм Retry, используя 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;
    }
}

основной метод:

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)

Пожалуйста, укажите, есть ли какие-то ошибки в моей реализации.

1 Ответ

1 голос
/ 17 июня 2020

Вы используете AspectJ, а не Spring AOP, поэтому ваш pointcut соответствует как

  • call() (источник вызова метода), так и
  • execution() ( целевой метод)

точек соединения, поэтому вы видите 4 вместо 2 вывода журнала. Вы могли бы легко выяснить это сами, если бы у вас была привычка всегда печатать полную точку соединения (а не только подпись или другую небольшую часть точки соединения) в начале вашего совета, по крайней мере, во время разработки. Вы можете прокомментировать это позже. Таким образом, вы можете просто добавить

System.out.println(proceedingJoinPoint);

, и вы поймете, что я имею в виду.

Самый простой способ решить проблему - ограничить pointcut либо вызовами, либо исполнениями. Я предлагаю последнее, если есть выбор, потому что лучше просто сплести один метод вместо 100 звонилок. Вы хотите изменить свой pointcut на (непроверено, в дороге пишу "свободные руки")

@Around("@annotation(main.Retry) && execution(* *(..))")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...