调用getProductContract返回空列表,Mono未执行问题如何解决
问题根因
你当前的代码采用了命令式编程的写法拼接响应式流,存在两个核心错误:
forEach中启动的getProductDetails、getProductContracts都是异步运行在boundedElastic线程池的任务,代码不会等待这些异步任务执行完成,就直接返回了还没被填充的resultList,所以拿到的永远是空列表。- 你没有正确拼接响应式流的执行链,手动创建集合收集结果的写法在响应式场景下完全不适用,且你没有正确触发流的订阅(响应式流只有被订阅才会执行,Service层无需手动订阅,只要返回正确的流结构,最终会由Spring WebFlux框架在Controller层完成订阅)。
正确实现代码
修改后的Service.java代码如下:
// Service.java public Mono<List<ProductContract>> getProductContract() { Set<String> productIdList = new HashSet<>(); productIdList.add("p123"); productIdList.add("p456"); // 将每个productId转换为对应的查询流,合并为Flux统一管理 return Flux.fromIterable(productIdList) // 异步查询每个product的详情,指定运行线程池 .flatMap(productId -> prodRepository.getProductDetails(productId) .subscribeOn(Schedulers.boundedElastic())) // 用详情返回的contractId查询对应合同列表 .flatMap(productDetail -> prodRepository.getProductContracts(productDetail.getProductContractId())) // 取合同列表的第一个元素,自动过滤空值 .mapNotNull(contracts -> contracts.stream().findFirst().orElse(null)) // 所有查询完成后自动收集为List,包装为Mono返回 .collectList() // 若需要打印结果大小可新增doOnNext操作 .doOnNext(resultList -> log.info("size {}", resultList.size())); }
逻辑说明
- 用
Flux.fromIterable把产品ID集合转换成响应式流,统一管理所有异步任务的执行生命周期 - 所有异步查询的逻辑都拼接到同一个执行链中,框架订阅后会自动等待所有任务执行完成,再返回填充完成的结果列表
- 无需手动创建集合、手动触发订阅,完全符合响应式编程的规范
内容的提问来源于stack exchange,提问作者sumit pramanik
相关产品推荐
相关产品推荐

