With my limited notion of AOP, I believe we can do things before and after the JoinPoint i.e. method in this case, but how can we wrap implementation as above?
Have you ever read the very good Spring AOP manual? One of the first things you would notice would be the explanation of advice types and that there is not only before and after, but also around advice. This is what you want to use.
Here is basically how it works:
Java helper classes:
package de.scrum_master.app;
public class SomeType {}
package de.scrum_master.app;
public class SomeResource implements AutoCloseable {
@Override public void close() throws Exception {}
}
Interfaces:
package de.scrum_master.app;
public interface X {
void methodX1();
int methodX2(String s);
}
package de.scrum_master.app;
public interface Y {
void methodY1();
String methodY2(int i);
void methodY3(SomeType s);
}
Interface implementation + driver application:
I implemented the example in AspectJ, not in Spring AOP. Thus you see no application context, but you know how to do that, don't you?
package de.scrum_master.app;
import org.springframework.stereotype.Component;
@Component
public class MyImpl implements X, Y {
@Override public void methodY1() { System.out.println("Y1"); methodX2("bar"); }
@Override public String methodY2(int i) { System.out.println("Y2"); return "dummy"; }
@Override public void methodY3(SomeType s) { System.out.println("Y3"); }
@Override public void methodX1() { System.out.println("X1"); methodY1(); }
@Override public int methodX2(String s) { System.out.println("X2"); return 42; }
public static void main(String[] args) {
MyImpl myImpl = new MyImpl();
myImpl.methodX1();
myImpl.methodX2("foo");
myImpl.methodY1();
myImpl.methodY2(11);
myImpl.methodY3(new SomeType());
}
}
Please note that both methodX1()
and methodY1()
call methods internally. This will be important with regard to the difference between Spring AOP and AspectJ later.
Aspect:
In Spring AOP you can omit the execution(* *(..)) &&
part, I just use it here in order to avoid other joinpoints such as call()
being intercepted and the log to get bloated. As Spring AOP does not know much else than execution()
it is not necessary there. The parentheses around the ... || ...
block of the pointcut can also go away.
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import de.scrum_master.app.SomeResource;
@Component
@Aspect
public class WrapMethodsAspect {
@Around("execution(* *(..)) && (within(de.scrum_master.app.X+) || within(de.scrum_master.app.Y+))")
public Object wrapperAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
System.out.println("Wrapping " + thisJoinPoint);
try (SomeResource res = new SomeResource()) {
return thisJoinPoint.proceed();
}
finally {
System.out.println("Unwrapping " + thisJoinPoint);
}
}
}
Console output with AspectJ:
Wrapping execution(void de.scrum_master.app.MyImpl.main(String[]))
Wrapping execution(void de.scrum_master.app.MyImpl.methodX1())
X1
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Unwrapping execution(void de.scrum_master.app.MyImpl.methodX1())
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Wrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Y2
Unwrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Y3
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Unwrapping execution(void de.scrum_master.app.MyImpl.main(String[]))
Two things you notice here:
- The execution of the static
main(..)
method is logged. This would not happen with Spring AOP.
- The internal method calls are logged. This would also not happen with Spring AOP.
Console output with Spring AOP:
Wrapping execution(void de.scrum_master.app.MyImpl.methodX1())
X1
Unwrapping execution(void de.scrum_master.app.MyImpl.methodX1())
Wrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
X2
Unwrapping execution(int de.scrum_master.app.MyImpl.methodX2(String))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Y1
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY1())
Wrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Y2
Unwrapping execution(String de.scrum_master.app.MyImpl.methodY2(int))
Wrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
Y3
Unwrapping execution(void de.scrum_master.app.MyImpl.methodY3(SomeType))
In most cases, Spring AOP is enough for Spring users. But if you need a more powerful approach in order to capture other types of pointcuts or e.g. internal, nested method calls, you would use AspectJ via load-time weaving (LTW).