如何让Spring DeferredResult在结果设置或超时后再继续执行?
问题描述
我希望程序能等待Spring应用中其他位置(比如其他API或事件处理器)设置的值。下面是我写的控制器及相关代码,需要等待结果设置后再执行后续操作,但目前获取myVar的代码会在值设置前就运行了。请问怎么让DeferredResult等待结果或超时,或者有没有其他实现方法?
Example.java
@RestController public class ExampleController { @Autowired RequestHolder requestHolder; @GetMapping("/hello") public String hello() { DeferredResult myRequest = new DeferredResult<>(); requestHolder.addRequest(myRequest); // 想办法等待myRequest被处理 String myVar = (String) myRequest.getResult(); /* 到这里myRequest要么超时,要么已经有值了 用myVar做一些操作 */ return "return something"; } }
RequestHolder.java
package com.example.demo; import org.springframework.stereotype.Component; import org.springframework.web.context.request.async.DeferredResult; import java.util.ArrayList; import java.util.List; @Component public class RequestHolder { private List<DeferredResult> requestList; public RequestHolder(){ this.requestList = new ArrayList<>(); } public void addRequest(DeferredResult request){ this.requestList.add(request); } public void clear(){ this.requestList.clear(); } public List<DeferredResult> getRequestList() { return requestList; } }
RequestHandler.java
@RestController public class RequestHandler { @Autowired RequestHolder requestHolder; @GetMapping("/setResult") public void setResult() { for (DeferredResult request: requestHolder.getRequestList()) { request.setResult("Hello World!"); } requestHolder.clear(); } }
解决方案
1. 修正DeferredResult的使用逻辑
你的代码问题在于直接调用getResult()——这个方法不会阻塞等待结果,DeferredResult的正确用法是返回给Spring容器,由Spring管理异步请求的生命周期,直到结果被设置或超时。修改ExampleController如下:
@RestController public class ExampleController { @Autowired RequestHolder requestHolder; @GetMapping("/hello") public DeferredResult<String> hello() { // 设置超时时间(比如5秒),超时后自动触发回调 DeferredResult<String> myRequest = new DeferredResult<>(5000L); // 超时处理逻辑 myRequest.onTimeout(() -> { myRequest.setErrorResult("请求超时,请稍后重试"); }); // 结果完成后的回调(拿到值后执行后续操作) myRequest.onCompletion(() -> { String myVar = (String) myRequest.getResult(); if (myVar != null) { // 在这里处理拿到结果后的业务逻辑 System.out.println("获取到结果:" + myVar); } }); requestHolder.addRequest(myRequest); // 返回DeferredResult,让Spring异步挂起请求等待结果 return myRequest; } }
这样Spring会将请求挂起,直到/setResult接口调用设置结果,或者超时时间到期。
2. 修复RequestHolder的线程安全问题
当前RequestHolder使用ArrayList存储请求,多线程环境下会出现并发修改异常,换成线程安全的容器:
@Component public class RequestHolder { // 使用CopyOnWriteArrayList保证多线程下的安全操作 private List<DeferredResult<String>> requestList = new CopyOnWriteArrayList<>(); public void addRequest(DeferredResult<String> request){ this.requestList.add(request); } public void clear(){ this.requestList.clear(); } public List<DeferredResult<String>> getRequestList() { return requestList; } }
3. 其他替代方案
如果你的场景更复杂,还可以考虑这些实现方式:
- CompletableFuture + 异步执行器:结合Spring的
AsyncTaskExecutor,用CompletableFuture实现异步等待逻辑 - 消息队列:比如用Redis的Pub/Sub机制,
/hello接口订阅消息,/setResult发布消息,收到消息后返回结果 - WebSocket:适合需要双向实时通信的场景,直接推送结果到客户端
内容的提问来源于stack exchange,提问作者Curtis_L
相关产品推荐
相关产品推荐

