Reputation: 6998
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" />
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.
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
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