You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 09:13:14