I have my ControllerLogger
class that has some methods with @Before
and @AfterReturning
annotations.
Will they start to be executed asynchronously if I put @Async
on each of them along with @EnableAsync
?
How then the proxies be resolved and created for the methods and will they be?
What strikes me first when reading your question is: Why don't you just try, instead of asking a question here and waiting for an answer? After one minute you would know.
The second question is: Why would you want to create a new thread every single time an aspect's advice is being executed? Would that really be faster than synchronous execution? From your aspect name ControllerLogger
, I conclude that all it does is logging. But anyway, maybe your logging is so slow that it actually makes sense to make it asynchronous. Usually, you can configure that for your logging framework already, so the aspect would not need to take care of it.
Finally, the answer to your question: I have never tried that before myself, but it took me two minutes to test:
System.out.println(Thread.currentThread() + " -> " + Thread.currentThread().getId());
to both your aspect advice and a target method.@Async
/ @EnableAsync
. Note the results.@Async
/ @EnableAsync
. Note the results.For me I saw something like this before:
Thread[main,5,main] -> 1
Thread[main,5,main] -> 1
Thread[main,5,main] -> 1
Thread[main,5,main] -> 1
And this after activating asynchronous execution (3 aspect advices executed):
Thread[main,5,main] -> 1
Thread[SimpleAsyncTaskExecutor-1,5,main] -> 18
Thread[SimpleAsyncTaskExecutor-2,5,main] -> 25
Thread[SimpleAsyncTaskExecutor-3,5,main] -> 26
So the answer is: Yes, aspect advices like @Before
or @After
for Spring AOP will be executed asynchronously.
Be careful with @Around
advices, though, because if the target methods (and thus also the around advice) returns a type other than void
or Future
(as documented in the @Async
annotation's Javadoc), you will get runtime exceptions because the asynchronously executed advice will return null
to the intercepted method first. So you would see an exception like this:
Exception in thread "main"
org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public int spring.aop.MyController.doSomething(java.lang.String,int)
at org.springframework.aop.framework.CglibAopProxy.processReturnType(CglibAopProxy.java:362)
at org.springframework.aop.framework.CglibAopProxy.access$000(CglibAopProxy.java:84)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:658)
at spring.aop.MyController$$EnhancerBySpringCGLIB$$c28d13a5.doSomething(<generated>)
at spring.aop.DemoApplication.main(DemoApplication.java:28)
So be sure to use @Async
+ @Around
only in cases for which asynchronous execution actually makes sense and for which the annotation was designed.
Update: The exception above will only appear for methods returning primitive types, e.g. if your method returns an int
and an around advice is executed and calling JoinPoint.proceed()
. If the same method would return Integer
instead, the around advice would execute without an error, but return null
, which is something your caller does not expect and would potentially break your program. So as I said, be careful how to use this with @Around
.
Update 2: Even if the target method returns a Future
but the around advice returns something other, e.g. Object
, proceed()
will return null
. Only if you make the around advice also have a return type of Future
, it actually works and the caller can handle the future as expected and after waiting for isDone()
actually receives the expected result.