如果我将@Async 方法放在一个切面上,它会异步执行吗?
Will an aspect be executed asynchronously if I put @Async method on it?
我的 ControllerLogger
class 有一些带有 @Before
和 @AfterReturning
注释的方法。
如果我将 @Async
与 @EnableAsync
一起放在它们中,它们会开始异步执行吗?
那么如何为这些方法解析和创建代理?它们会是什么?
在阅读您的问题时,首先让我印象深刻的是:您为什么不直接尝试,而不是在这里提问并等待答案?一分钟后你就知道了。
第二个问题是:为什么要在每次执行方面的建议时都创建一个新任务?这真的会比同步执行更快吗?从您的方面名称 ControllerLogger
我得出结论,它所做的只是记录。但是无论如何,也许您的日志记录速度太慢以至于使其异步实际上是有意义的。通常你可以为你的日志框架配置它,所以方面不需要处理它。
终于回答了你的问题:我自己之前从未尝试过,但我花了两分钟来测试:
- 在方面建议和目标方法中添加类似
System.out.println(Thread.currentThread() + " -> " + Thread.currentThread().getId());
的语句。
- 运行 没有
@Async
/ @EnableAsync
。注意结果。
- 运行 再次
@Async
/ @EnableAsync
。注意结果。
对我来说,我以前看过这样的东西:
Thread[main,5,main] -> 1
Thread[main,5,main] -> 1
Thread[main,5,main] -> 1
Thread[main,5,main] -> 1
并且在激活异步执行之后(执行了 3 个方面的建议):
Thread[main,5,main] -> 1
Thread[SimpleAsyncTaskExecutor-1,5,main] -> 18
Thread[SimpleAsyncTaskExecutor-2,5,main] -> 25
Thread[SimpleAsyncTaskExecutor-3,5,main] -> 26
所以答案是:是的,Spring AOP 的方面建议如 @Before
或 @After
将异步执行。
注意 @Around
建议,因为如果目标方法(以及周围建议)return 是 void
或 Future
以外的类型(如 @Async
annotation's Javadoc 中所述),您将获得运行时异常,因为异步执行的通知将首先 return null
拦截方法。所以你会看到这样的异常:
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[=12=]0(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)
因此,请务必仅在异步执行实际有意义且注解是为其设计的情况下使用 @Async
+ @Around
。
更新: 上面的异常只会出现在 returning 原始类型的方法中,例如如果你的方法 returns 一个 int
和一个环绕通知被执行并调用 JoinPoint.proceed()
。如果相同的方法将 return Integer
改为执行,around advice 将在没有错误的情况下执行,但是 return null
,这是您的调用者不期望的并且可能会中断的事情你的程序。所以正如我所说,请注意如何将其与 @Around
.
一起使用
更新 2: 即使目标方法 return 是 Future
但周围建议 return 是其他的,例如Object
、proceed()
将 return null
。仅当您使 around advice 也具有 return 类型的 Future
时,它才真正起作用并且调用者可以按预期处理未来,并且在等待 isDone()
实际收到预期结果之后。
我的 ControllerLogger
class 有一些带有 @Before
和 @AfterReturning
注释的方法。
如果我将 @Async
与 @EnableAsync
一起放在它们中,它们会开始异步执行吗?
那么如何为这些方法解析和创建代理?它们会是什么?
在阅读您的问题时,首先让我印象深刻的是:您为什么不直接尝试,而不是在这里提问并等待答案?一分钟后你就知道了。
第二个问题是:为什么要在每次执行方面的建议时都创建一个新任务?这真的会比同步执行更快吗?从您的方面名称 ControllerLogger
我得出结论,它所做的只是记录。但是无论如何,也许您的日志记录速度太慢以至于使其异步实际上是有意义的。通常你可以为你的日志框架配置它,所以方面不需要处理它。
终于回答了你的问题:我自己之前从未尝试过,但我花了两分钟来测试:
- 在方面建议和目标方法中添加类似
System.out.println(Thread.currentThread() + " -> " + Thread.currentThread().getId());
的语句。 - 运行 没有
@Async
/@EnableAsync
。注意结果。 - 运行 再次
@Async
/@EnableAsync
。注意结果。
对我来说,我以前看过这样的东西:
Thread[main,5,main] -> 1
Thread[main,5,main] -> 1
Thread[main,5,main] -> 1
Thread[main,5,main] -> 1
并且在激活异步执行之后(执行了 3 个方面的建议):
Thread[main,5,main] -> 1
Thread[SimpleAsyncTaskExecutor-1,5,main] -> 18
Thread[SimpleAsyncTaskExecutor-2,5,main] -> 25
Thread[SimpleAsyncTaskExecutor-3,5,main] -> 26
所以答案是:是的,Spring AOP 的方面建议如 @Before
或 @After
将异步执行。
注意 @Around
建议,因为如果目标方法(以及周围建议)return 是 void
或 Future
以外的类型(如 @Async
annotation's Javadoc 中所述),您将获得运行时异常,因为异步执行的通知将首先 return null
拦截方法。所以你会看到这样的异常:
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[=12=]0(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)
因此,请务必仅在异步执行实际有意义且注解是为其设计的情况下使用 @Async
+ @Around
。
更新: 上面的异常只会出现在 returning 原始类型的方法中,例如如果你的方法 returns 一个 int
和一个环绕通知被执行并调用 JoinPoint.proceed()
。如果相同的方法将 return Integer
改为执行,around advice 将在没有错误的情况下执行,但是 return null
,这是您的调用者不期望的并且可能会中断的事情你的程序。所以正如我所说,请注意如何将其与 @Around
.
更新 2: 即使目标方法 return 是 Future
但周围建议 return 是其他的,例如Object
、proceed()
将 return null
。仅当您使 around advice 也具有 return 类型的 Future
时,它才真正起作用并且调用者可以按预期处理未来,并且在等待 isDone()
实际收到预期结果之后。