Will an aspect be executed asynchronously if I put @Async method on it?

Pasha :

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?

kriegaex :

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 task 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 it 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:

  • Add a statement like System.out.println(Thread.currentThread() + " -> " + Thread.currentThread().getId()); to both your aspect advice and a target method.
  • Run without @Async / @EnableAsync. Note the results.
  • Run again with @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.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=309855&siteId=1