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

OpenAPI与Spring Boot3:契约优先模式下为特定端点用DeferredResult的方法

契约优先模式下特定端点使用DeferredResult的可行方案

方案一:OpenAPI扩展标记 + 拦截器局部处理

  • 在你的OpenAPI契约中,给需要异步处理的特定端点添加自定义扩展字段,比如x-use-deferred-result: true
  • 实现一个Spring MVC HandlerInterceptor,在请求预处理阶段,根据当前请求的URI匹配契约中的端点元数据,检查是否携带该扩展标记
  • 如果标记为true,就将同步处理逻辑转为DeferredResult异步模式,避免全局包装所有端点

示例代码:

public class DeferredResultInterceptor implements HandlerInterceptor {
    // 假设已将OpenAPI契约的端点元数据加载到本地缓存
    private final Map<String, Boolean> asyncEndpointCache = loadAsyncEndpointsFromContract();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestUri = request.getRequestURI();
        if (Boolean.TRUE.equals(asyncEndpointCache.get(requestUri))) {
            DeferredResult<Object> deferredResult = new DeferredResult<>();
            // 提交业务逻辑到异步线程池执行
            CompletableFuture.runAsync(() -> {
                Object businessResult = executeAsyncBusinessLogic(request);
                deferredResult.setResult(businessResult);
            });
            // 将DeferredResult绑定到请求上下文,替换原同步返回值
            request.setAttribute("asyncResult", deferredResult);
        }
        return true;
    }
}

方案二:自定义注解 + 返回值处理器

  • 保留现有代码生成流程,在生成后的Controller方法中,给需要异步的方法手动添加自定义注解(比如@UseDeferredResult)
  • 实现HandlerMethodReturnValueHandler,在处理返回值时检查方法是否带有该注解,若存在则自动将返回值包装为DeferredResult

示例代码:

// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseDeferredResult {}

// 生成后添加注解的Controller方法
@RestController
public class GeneratedOrderController {
    @UseDeferredResult
    @GetMapping("/api/orders/{id}")
    public OrderDetail getOrderDetail(@PathVariable String id) {
        return orderService.getDetail(id);
    }
}

// 自定义返回值处理器
public class DeferredResultHandler implements HandlerMethodReturnValueHandler {
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return returnType.hasMethodAnnotation(UseDeferredResult.class);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, 
                                 ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
        DeferredResult<Object> deferredResult = new DeferredResult<>();
        // 异步包装返回值
        CompletableFuture.supplyAsync(() -> returnValue)
                .thenAccept(deferredResult::setResult)
                .exceptionally(ex -> {
                    deferredResult.setErrorResult(ex);
                    return null;
                });
        mavContainer.setRequestHandled(true);
        webRequest.getNativeResponse(HttpServletResponse.class)
                .setAttribute(DeferredResult.class.getName(), deferredResult);
    }
}

方案三:动态代理层局部包装

  • 基于代码生成的Controller接口,创建动态代理实例,在代理逻辑中对指定端点的返回值进行DeferredResult包装
  • 将代理实例注册到Spring容器,替代原生成的Controller Bean,全程无需修改生成代码或契约模板

核心逻辑示例:

public class DeferredResultProxyCreator {
    public static <T> T createAsyncProxy(T targetController, Set<String> asyncEndpointPaths) {
        return (T) Proxy.newProxyInstance(
                targetController.getClass().getClassLoader(),
                targetController.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    // 从方法注解中解析对应端点路径
                    String endpoint = resolveEndpointFromMethodAnnotations(method);
                    if (asyncEndpointPaths.contains(endpoint)) {
                        DeferredResult<Object> deferredResult = new DeferredResult<>();
                        // 异步执行原方法逻辑
                        CompletableFuture.supplyAsync(() -> {
                            try {
                                return method.invoke(targetController, args);
                            } catch (Exception e) {
                                deferredResult.setErrorResult(e);
                                return null;
                            }
                        }).thenAccept(deferredResult::setResult);
                        return deferredResult;
                    }
                    // 非异步端点直接返回原结果
                    return method.invoke(targetController, args);
                });
    }
}

以上三种方案都无需修改mustache模板或打破现有工作流程,通过局部扩展机制实现特定端点的DeferredResult包装需求。

内容的提问来源于stack exchange,提问作者Sayros

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:02:20