RandomQuestion
RandomQuestion

Reputation: 6998

Spring AOP: Aspect not working on called method

This is my first time with AOP so this might be very noob question.

public class MyAspect implements AspectI {

public void method1() throws AsyncApiException {
    System.out.println("In Method1. calling method 2");
    method2();
}

@RetryOnInvalidSessionId
public void method2() throws AsyncApiException {
    System.out.println("In Method2, throwing exception");
    throw new AsyncApiException("method2", AsyncExceptionCode.InvalidSessionId);
}

public void login() {
    System.out.println("Logging");
}

InvalidSessionHandler looks like this.

@Aspect
public class InvalidSessionIdHandler implements Ordered {

    @Around("@annotation(com.pkg.RetryOnInvalidSessionId)")
    public void reLoginAll(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Hijacked call: " + joinPoint.getSignature().getName() + " Proceeding");
        try {
            joinPoint.proceed();
        } catch (Throwable e) {
            if (e instanceof AsyncApiException) {
                AsyncApiException ae = (AsyncApiException) e;
                if (ae.getExceptionCode() == AsyncExceptionCode.InvalidSessionId) {
                    System.out.println("invalid session id. relogin");
                    AspectI myAspect = (AspectI) joinPoint.getTarget();
                    myAspect.login();
                    System.out.println("Login done. Proceeding again now");
                    joinPoint.proceed();
                }
            }
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

Spring configuration

<aop:aspectj-autoproxy />
<bean id="myAspect" class="com.pkg.MyAspect" />
<bean id="invalidSessionIdHandler" class="com.pkg.InvalidSessionIdHandler" />  
  1. My intent is when I call myAspect.method1() which in turns calls method2, if method2 throws InvalidSessionId Exception, then only method2 should be retried. But above code does not seem to do anything. It just immediately returns after exception is thrown from method2. However if I put @RetryOnInvalidSessionId on method1 then whole method1 is retried.

  2. For learning I kept method2 is public but in actual I want it to be private. I am out of clue here, how to retry private method.

Any suggestions would be helpful.

Thanks

Upvotes: 3

Views: 9360

Answers (1)

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280168

This is not possible with your current setup. With Spring's AOP features, your class InvalidSessionIdHandler will get created as a bean and then scanned for annotations/method signatures/etc. relevant to your MyAspect class. It will find method2() and therefore create a proxy wrapping the bean it's already created. The proxy will have the behavior from your advice.

Spring will the inject this (proxy) bean where you need it. For example:

public class MyClass {
   @Autowired
   private MyAspect aspect;

   public void callMethod2() {
       aspect.method2();
   }
}

In this case, the MyClass object has a reference to the proxy. When it calls aspect.method2(), the added behavior will be executed.

In your code, however, you're expecting to call method2() within method1()

public void method1() throws AsyncApiException {
    System.out.println("In Method1. calling method 2");
    method2();
}

which is within your MyAspect class. Technically, what is happening here is method2() getting called on this as this.method2(). this is a reference to the actual object, not the proxy. It will therefore not execute any additional behavior.

The AOP Spring documentation explains this in more detail.

The workaround here is to refactor so that method2() is in another class/object or to call it from outside, ie. not from method1().

Upvotes: 5

Related Questions