如何用Spring WebFlux设计非阻塞REST控制器及异步链式调用?
WebFlux中串联异步调用并返回结果的正确实现
当前问题分析
直接调用credentialMono.subscribe(credential -> callApi(credential))是错误的,原因如下:
subscribe是触发异步执行的操作,但它不会将后续API调用的结果整合到返回给控制器的Mono中。- 控制器拿到的
Mono会立即完成,不会等待API调用的结果,导致客户端无法获取到正确的响应。
正确实现方式
WebFlux的核心是通过响应式操作符构建链式调用,这里需要使用flatMap操作符,它可以将一个Mono<T>转换为另一个Mono<R>,完美适配你的场景:
修改ResourceService的getResource方法:
@Override public Mono<String> getResource(ResourceType resourceType) { Mono<ServerCredential> credentialMono = credentialService.getServerCredential(resourceType); // 使用flatMap串联异步操作:当credentialMono拿到结果后,调用searchResource发起API请求 return credentialMono.flatMap(this::searchResource); }
补充优化:WebClient的复用
每次调用searchResource都创建新的WebClient实例会带来性能开销,建议通过WebClient.Builder复用配置(Spring Boot自动提供该Bean):
- 注入
WebClient.Builder:
private final WebClient.Builder webClientBuilder; // 构造方法注入 public ResourceServiceImpl(WebClient.Builder webClientBuilder) { this.webClientBuilder = webClientBuilder; }
- 修改
searchResource方法:
private Mono<String> searchResource(ServerCredential credential) { WebClient client = webClientBuilder.baseUrl(credential.getServer().getServerUrl()).build(); return client.post() .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON) // 如果需要发送请求体,添加.bodyValue(请求对象) .retrieve() .bodyToMono(String.class) .retry(RETRY_COUNT); }
原理说明
flatMap会等待credentialMono成功发射ServerCredential对象,然后调用searchResource方法发起WebClient请求,返回新的Mono<String>。- 整个方法返回的
Mono<String>会被控制器返回给WebFlux框架,框架会自动处理订阅、异步调度,等待API请求完成后将结果返回给客户端。
内容的提问来源于stack exchange,提问作者Jonathan Hagen
相关产品推荐
相关产品推荐

