从另一个异步方法调用的 Spring 异步方法

Posted

技术标签:

【中文标题】从另一个异步方法调用的 Spring 异步方法【英文标题】:Spring async method called from another async method 【发布时间】:2014-09-13 22:23:18 【问题描述】:

我正在使用 Spring 4,但我注意到一个奇怪的行为......如果我从一个普通的实例方法多次调用异步方法,那么它们都在不同的线程中调用并在随机时间完成。但是,如果我从另一个异步方法多次调用一个异步方法,那么它们会按顺序完成。我有这样的事情:

@Async
public void nonAsyncMethod() 
  for (int i = 0; i < 30; i++) 
     asyncMethod();
  


@Async
public void asyncMethod() 
   ... something here

我正在使用默认的异步执行器。我应该使用不同的吗?然而,这个执行器不重用任何线程并且每次都启动另一个,所以应该没问题......这可能只是巧合吗?但是我已经尝试了超过 10 次,如果我将第一种方法恢复为非异步,那么它们会随机完成

【问题讨论】:

如果第一个异步方法调用的非异步方法调用了第二个异步方法(多次)怎么办? 【参考方案1】:

您所描述的是 Spring AOP 的一个经典陷阱。

简而言之,为了让 Spring 能够提供在运行时为您的类创建代理所需的异步行为。然后代理在调用您的代码之前和/或之后执行它需要做的任何事情。但是在您的情况下,代理机制并未应用于第二种方法。

当你的类的 bean 通过 Spring 注入到其他组件时,Spring 确实注入了代理。因此调用了代理的相关方法。但是,当您从类内部调用方法时,Spring AOP 的限制意味着代理永远不会发挥作用,而是调用常规方法 - 没有额外的功能。

这就是为什么asyncMethod 总是与调用它的同一个类中的另一个方法在同一个线程上执行。

查看 this 优秀的博文以及 this Spring 文档的一部分。

有一些解决问题的方法(查看this)不需要你重构你的代码,但是如果你想要异步在这两种方法上工作,最简单的事情就是重构第二种方法进入另一个类。

【讨论】:

@KarthikR 很高兴你喜欢它!谢谢! 这是一个很好的答案!有什么技巧可以轻松克服? @AmanuelNega 最简单的解决方案通常是将方法重构为另一个类(当然也需要是一个 Spring bean)

以上是关于从另一个异步方法调用的 Spring 异步方法的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot:使用异步方法作为同步方法

Spring中@Async注解实现“方法”的异步调用

Spring Boot 微服务异步调用 @EnableAsync @Async

spring异步方法@Async

spring使用@Async注解异步处理

使用Spring中@Async注解实现异步调用