如果我将 @Async 方法放在一个方面会异步执行吗?

Pav*_*vel 3 java aop spring asynchronous

我有我的ControllerLogger类,它有一些方法与@Before@AfterReturning注释。

如果我把@Async它们都放在一起,它们会开始异步执行@EnableAsync吗?

那么如何为这些方法解析和创建代理,它们将如何?

kri*_*aex 13

在阅读您的问题时,首先让我印象深刻的是:您为什么不尝试而不是在这里提出问题并等待答案?一分钟后你就知道了。

第二个问题是:为什么每次执行方面的建议时都想创建一个新任务?那真的会比同步执行更快吗?从你的方面名称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
Run Code Online (Sandbox Code Playgroud)

这在激活异步执行之后(执行了 3 个方面建议):

Thread[main,5,main] -> 1
Thread[SimpleAsyncTaskExecutor-1,5,main] -> 18
Thread[SimpleAsyncTaskExecutor-2,5,main] -> 25
Thread[SimpleAsyncTaskExecutor-3,5,main] -> 26
Run Code Online (Sandbox Code Playgroud)

所以答案是:是的,像@Before@After用于 Spring AOP 的方面建议将异步执行。

但是要小心@Around通知,因为如果目标方法(以及周围的通知)返回voidor以外的类型Future(如@Async注释的 Javadoc 中所述),您将获得运行时异常,因为异步执行的通知将返回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$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)
Run Code Online (Sandbox Code Playgroud)

因此,请确保仅在异步执行实际上有意义并且设计了注释的情况下才使用@Async+ @Around


更新:上面的异常只会出现在返回原始类型的方法中,例如,如果您的方法返回 anint并且一个 around 建议被执行并调用JoinPoint.proceed(). 如果相同的方法会返回Integer,那么 around 建议将执行而不会出错,但是 return null,这是您的调用者不期望的并且可能会破坏您的程序。所以正如我所说,小心如何将它与@Around.


更新 2:即使目标方法返回 aFuture但围绕建议返回其他内容,例如Objectproceed()将返回null。只有当你让 around 通知也有一个返回类型时Future,它才真正起作用,调用者可以按预期处理未来,等待isDone()实际收到预期结果后。