如果我将@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 是 voidFuture 以外的类型(如 @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 是其他的,例如Objectproceed() 将 return null。仅当您使 around advice 也具有 return 类型的 Future 时,它才真正起作用并且调用者可以按预期处理未来,并且在等待 isDone() 实际收到预期结果之后。