0

0

Spring Reactive:等待所有 Mono 完成后再执行后续操作

碧海醫心

碧海醫心

发布时间:2025-07-30 18:22:11

|

205人浏览过

|

来源于php中文网

原创

spring reactive:等待所有 mono 完成后再执行后续操作

在 Spring Reactive 编程中,经常会遇到需要并发调用多个外部 API,并将所有 API 返回的结果进行聚合处理的场景。例如,你需要从多个服务获取 Swagger 定义,并将它们合并成一个总的 Swagger 定义。在这种情况下,你需要确保所有 API 调用都完成后,才能执行后续的聚合逻辑。

直接使用 Mono.zip 或 Flux.merge 等操作符虽然可以实现并发调用,但无法方便地获取每个 API 调用的服务名,也难以处理 API 调用失败的情况。本文将介绍一种使用 Flux 和 collectList 操作符来实现并发调用和结果聚合的方法,并提供处理错误日志的示例代码。

使用 Flux 和 collectList 实现并发调用和结果聚合

首先,我们需要创建一个临时类,用于存储 API 返回的数据和服务名:

record SwaggerService(SwaggerServiceData swaggerServiceData, String serviceName) {
    boolean hasData() {
        return swaggerServiceData != null;
    }
}

然后,我们可以使用 Flux.fromStream 将服务名和 URL 的映射转换为 Flux,并使用 flatMap 操作符来并发调用 API:

Flux.fromStream(swaggerProperties.getUrls().entrySet().stream())
    .flatMap((e) -> {
        Mono swaggerDefinitionForAPI = getSwaggerDefinitionForAPI(e.getKey(), e.getValue());
        return swaggerDefinitionForAPI.map(swaggerServiceData -> new SwaggerService(swaggerServiceData, e.getKey()));
    })
    .filter(SwaggerService::hasData)
    .map(swaggerService -> {
        String content = getJSON(swaggerService.swaggerServiceData());
        definitionContext.addServiceDefinition(swaggerService.serviceName(), content);
        return swaggerService.swaggerServiceData();
    })
    .collectList()
    .map(this::getAllServicesApiSwagger)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .subscribe(e -> {
        String allApiContent = getJSON(e);
        definitionContext.addServiceDefinition("All", allApiContent);
    });

这段代码的流程如下:

迷你天猫商城
迷你天猫商城

迷你天猫商城是一个基于Spring Boot的综合性B2C电商平台,需求设计主要参考天猫商城的购物流程:用户从注册开始,到完成登录,浏览商品,加入购物车,进行下单,确认收货,评价等一系列操作。 作为迷你天猫商城的核心组成部分之一,天猫数据管理后台包含商品管理,订单管理,类别管理,用户管理和交易额统计等模块,实现了对整个商城的一站式管理和维护。所有页面均兼容IE10及以上现代浏览器。部署方式1、项目

下载
  1. Flux.fromStream:将 swaggerProperties.getUrls() 的 entrySet 转换为 Stream,再将 Stream 转换为 Flux。
  2. flatMap:对于 Flux 中的每个元素(服务名和 URL 的映射),并发调用 getSwaggerDefinitionForAPI 方法获取 Swagger 定义。flatMap 允许并发执行多个 Mono。
  3. map:将 SwaggerServiceData 和服务名封装到 SwaggerService 对象中。
  4. filter:过滤掉 SwaggerServiceData 为 null 的情况。
  5. map:将 SwaggerServiceData 转换为 JSON 字符串,并将其添加到 definitionContext 中。
  6. collectList:将所有 SwaggerServiceData 收集到一个 List 中,并将其转换为 Mono>。这是关键的一步,它会将所有并发的 Mono 的结果收集起来,并在所有 Mono 完成后才发出结果。
  7. map:调用 getAllServicesApiSwagger 方法,将所有 Swagger 定义合并成一个总的 Swagger 定义。
  8. filter:过滤掉 Optional 为空的的情况。
  9. map:从 Optional 中获取 SwaggerServiceData。
  10. subscribe:订阅 Mono,并在所有 API 调用完成后,将总的 Swagger 定义添加到 definitionContext 中。

处理 API 调用失败的情况

如果 API 调用失败,getSwaggerDefinitionForAPI 方法可能会返回一个空的 Mono。为了处理这种情况,可以使用 flatMap 和 Mono.empty():

Flux.fromStream(swaggerProperties.getUrls().entrySet().stream())
    .flatMap((e) -> {
        Mono swaggerDefinitionForAPI = getSwaggerDefinitionForAPI(e.getKey(), e.getValue());
        return swaggerDefinitionForAPI
            .flatMap(swaggerServiceData -> {
                if(swaggerServiceData != null) {
                    return Mono.just(new SwaggerService(swaggerServiceData, e.getKey()));
                } else {
                    log.error("Skipping service id : {} Error : Could not get Swagger definition from API ", e.getKey());
                    return Mono.empty();
                }
            });
    })
    .map(swaggerService -> {
        String content = getJSON(swaggerService.swaggerServiceData());
        definitionContext.addServiceDefinition(swaggerService.serviceName(), content);
        return swaggerService.swaggerServiceData();
    })
    .collectList()
    .map(this::getAllServicesApiSwagger)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .subscribe(e -> {
        String allApiContent = getJSON(e);
        definitionContext.addServiceDefinition("All", allApiContent);
    });

在这个版本中,如果 swaggerServiceData 为 null,则会记录一条错误日志,并返回 Mono.empty()。Mono.empty() 不会发出任何元素,因此 collectList 不会收集到这个结果,从而避免了因 API 调用失败而导致的问题。

总结

通过使用 Flux 和 collectList 操作符,可以方便地实现并发调用多个 API,并等待所有 API 调用完成后再执行后续的聚合操作。同时,可以使用 flatMap 和 Mono.empty() 来处理 API 调用失败的情况,以确保程序的健壮性。这种方法可以应用于各种需要并发调用多个服务并将结果聚合的场景,例如微服务架构中的数据聚合、批量处理等。为了提高代码的可读性,可以将 lambda 表达式封装成单独的方法。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

98

2025.08.06

json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

402

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

528

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

306

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

74

2025.09.10

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

229

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

433

2024.03.01

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

248

2023.08.03

vlookup函数使用大全
vlookup函数使用大全

本专题整合了vlookup函数相关 教程,阅读专题下面的文章了解更多详细内容。

28

2025.12.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号