Java控制器如何获取异步Service中异步方法返回的数据?
Java @Async异步方法获取返回值解决方案
问题根因
当方法被@Async注解修饰后,Spring会通过代理机制异步执行该方法逻辑,调用方触发方法后会立刻返回,不会等待逻辑执行完成。你当前的写法存在两个核心问题:
- 直接通过类名静态调用
MG.messageGetter,没有使用Spring托管的Bean实例,@Async注解根本不会生效 - 异步方法返回值定义为普通
String类型,调用方无法接收异步执行后的返回结果,拿到的值永远为null
修正步骤
第一步:开启异步支持 + 修正Service定义
首先要在项目启动类或者异步配置类上添加@EnableAsync注解,开启Spring异步能力,再修正MG类的写法:
@Service public class MG { @Async public CompletableFuture<String> messageGetter(Integer z) { // 此处可替换为实际业务逻辑 return CompletableFuture.completedFuture("HELLOFRIEND"); } }
第二步:修正Controller调用逻辑
注入MG的Spring托管实例,需要同步拿到返回值的场景可通过CompletableFuture的get()方法阻塞等待异步结果返回:
@RestController public class XyzController { // 注入Spring托管的MG实例,禁止直接静态调用类方法 @Autowired private MG mg; @PostMapping("/xyz") void getThatMessageAndEmail(@RequestBody Integer z) throws Exception { CompletableFuture<String> futureResult = mg.messageGetter(z); // 阻塞等待异步执行完成,获取返回值 String messageToCatch = futureResult.get(); System.out.println(functionToConcat(z, messageToCatch)); } // 你的字符串拼接方法自行实现即可 private String functionToConcat(Integer z, String msg) { return z + msg; } }
如果不需要阻塞Controller主线程,可使用回调方式非阻塞处理结果:
@PostMapping("/xyz") void getThatMessageAndEmail(@RequestBody Integer z) { mg.messageGetter(z).thenAccept(messageToCatch -> { System.out.println(functionToConcat(z, messageToCatch)); }); }
注意事项
- 异步方法必须是public修饰,不能是static、private,否则Spring代理会失效
- 异步方法不要和调用方写在同一个类中,否则会绕过代理导致
@Async不生效 get()方法可以设置超时时间,避免异步逻辑故障导致主线程长时间阻塞,写法为futureResult.get(3, TimeUnit.SECONDS)
内容的提问来源于stack exchange,提问作者ripunjoym1998
相关产品推荐
相关产品推荐

