Spring Boot响应式编程中如何将Mono<List<something>>转为List<something>
首先明确:Mono<T>是Reactor提供的异步值包装类型,不存在直接把Mono<List<T>>强转为List<T>的“类型转换”逻辑,所有取值操作要么在响应式操作符内完成,要么在明确允许阻塞的代码边界场景通过阻塞方法获取,分两种场景处理:
场景1:处于响应式调用链路中(如WebFlux接口返回、响应式服务逻辑组装)
这种场景完全不需要手动提取Mono内的List值。你代码里写的.map(a -> {return a;})是无意义的恒等操作,直接删除即可,repo.findAll().collectList()本身就已经是Mono<List<你的实体类型>>类型,Spring WebFlux框架会在请求处理的最后自动订阅这个Mono,取出内部的List序列化成响应返回。
如果需要对List做业务处理,直接在操作符内部操作即可,操作符的入参就是你要的原生List实例,示例代码:Mono<List<YourEntity>> listMono = repo.findAll().collectList() .map(entityList -> { // 这里的entityList就是你需要的List类型,直接写业务逻辑即可 return entityList.stream() .filter(Objects::nonNull) .collect(Collectors.toList()); }); // WebFlux层直接返回Mono即可,不需要手动拆值 @GetMapping("/list") public Mono<List<YourEntity>> getEntityList() { return listMono; }注意:响应式编程规范要求不要在链路中手动阻塞拿值,所有对包装内值的处理都要通过map/flatMap等操作符完成,随意阻塞会破坏响应式非阻塞模型,导致吞吐量骤降。
场景2:处于非响应式的同步代码场景,必须拿到原生List对象
这类场景一般是单元测试、定时任务、传统Servlet线程调用响应式组件这类不在响应式事件循环线程内的场景,可以用block()方法阻塞等待值返回,Spring Boot 2.7.0版本自带的Reactor版本完全支持该方法,建议设置合理超时避免无限阻塞:// 最长阻塞5秒等待结果返回 List<YourEntity> entityList = repo.findAll() .collectList() .block(Duration.ofSeconds(5));警告:严禁在Netty EventLoop等响应式工作线程内调用
block()方法,Reactor会直接抛出BlockingOperationError异常,同时会造成线程阻塞完全抵消响应式编程的性能优势。
内容的提问来源于stack exchange,提问作者Erick Gonzalez

