Project Reactor:从Mono中提取字段并进行非阻塞链式调用

Project Reactor:从Mono中提取字段并进行非阻塞链式调用

本文深入探讨在Project Reactor中如何从一个Mono对象中提取特定字段,并将其作为参数传递给另一个非阻塞的响应式操作。我们将详细介绍如何利用flatMap操作符实现顺序依赖的异步调用,以及如何结合Mono.zip来聚合多个响应式操作的结果,从而构建高效、非阻塞的数据处理流程。

响应式编程中,我们经常会遇到这样的场景:一个异步操作的结果(例如,一个mono)中包含我们需要的数据(例如,truckid),而这个数据又需要作为参数来启动另一个异步操作(例如,vehicleservice.getbytruckid(truckid))。传统的阻塞式编程会直接获取order对象并提取truckid,但在project reactor这样的非阻塞框架中,我们需要采用响应式的方式来处理这种依赖关系。

核心挑战:从Mono中提取字段并进行链式调用

假设我们有两个服务方法,它们都返回Mono对象:

orderService.getById(UUID id) 返回 MonovehicleService.getByTruckId(UUID truckId) 返回 Mono

Order类定义如下:

public class Order {    private UUID id;    private String name;    private UUID truckId; // 我们需要提取的字段    // 构造函数、Getter/Setter等}

我们的目标是从Mono中获取truckId,并用它来调用vehicleService.getByTruckId,同时确保整个过程是非阻塞的。

解决方案一:仅关注后续操作结果 (使用 flatMap)

如果我们的最终目标仅仅是获取第二个操作(例如获取Truck)的结果,那么flatMap是实现这一目标的核心操作符。flatMap可以将一个Mono发出的元素转换为另一个Mono,并将这个新的Mono的元素作为最终结果发出。

示例代码:

import reactor.core.publisher.Mono;import java.util.UUID;// 模拟的服务接口interface OrderService {    Mono getById(UUID id);}interface VehicleService {    Mono getByTruckId(UUID truckId);}// 模拟的Order和Truck类class Order {    private UUID id;    private String name;    private UUID truckId;    public Order(UUID id, String name, UUID truckId) {        this.id = id;        this.name = name;        this.truckId = truckId;    }    public UUID getTruckId() {        return truckId;    }    @Override    public String toString() {        return "Order{" + "id=" + id + ", name='" + name + "', truckId=" + truckId + '}';    }}class Truck {    private UUID id;    private String model;    public Truck(UUID id, String model) {        this.id = id;        this.model = model;    }    @Override    public String toString() {        return "Truck{" + "id=" + id + ", model='" + model + '}';    }}public class ReactiveChainingExample {    private OrderService orderService;    private VehicleService vehicleService;    public ReactiveChainingExample(OrderService orderService, VehicleService vehicleService) {        this.orderService = orderService;        this.vehicleService = vehicleService;    }    public Mono getTruckForOrder(UUID orderId) {        Mono orderMono = orderService.getById(orderId);        // 使用flatMap从Order中提取truckId并调用getByTruckId        Mono truckMono = orderMono.flatMap(order -> vehicleService.getByTruckId(order.getTruckId()));        return truckMono;    }    public static void main(String[] args) {        // 模拟服务实现        OrderService mockOrderService = id -> Mono.just(new Order(id, "Order A", UUID.randomUUID()));        VehicleService mockVehicleService = truckId -> Mono.just(new Truck(truckId, "Volvo FH"));        ReactiveChainingExample example = new ReactiveChainingExample(mockOrderService, mockVehicleService);        UUID testOrderId = UUID.randomUUID();        example.getTruckForOrder(testOrderId)               .subscribe(                   truck -> System.out.println("成功获取到卡车信息: " + truck),                   error -> System.err.println("获取卡车信息失败: " + error.getMessage())               );        // 确保主线程不会立即退出,以便异步操作完成        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            Thread.currentThread().interrupt();        }    }}

解析:orderMono.flatMap(order -> vehicleService.getByTruckId(order.getTruckId())) 这行代码是关键。当orderMono发出一个Order对象时,flatMap会接收到这个Order,然后执行提供的Lambda表达式。Lambda表达式中,我们从Order对象中获取truckId,并用它来调用vehicleService.getByTruckId,这会返回一个新的Mono。flatMap会将这个Mono扁平化,使其发出的Truck对象成为最终流的元素。

小鸽子助手 小鸽子助手

一款集成于WPS/Word的智能写作插件

小鸽子助手 55 查看详情 小鸽子助手

解决方案二:聚合多个操作结果 (使用 flatMap 和 Mono.zip)

在某些情况下,我们不仅需要后续操作的结果,还需要原始操作的结果,或者需要将两者聚合到一个新的数据结构中。这时,我们可以结合flatMap和Mono.zip来实现。

首先,定义一个用于聚合结果的类:

class OrderWithTruck {    private Order order;    private Truck truck;    public OrderWithTruck(Order order, Truck truck) {        this.order = order;        this.truck = truck;    }    // Getter方法    public Order getOrder() { return order; }    public Truck getTruck() { return truck; }    @Override    public String toString() {        return "OrderWithTruck{" + "order=" + order + ", truck=" + truck + '}';    }}

示例代码:

import reactor.core.publisher.Mono;import reactor.util.function.Tuple2; // 用于Mono.zip的默认返回类型import java.util.UUID;// ... (OrderService, VehicleService, Order, Truck, OrderWithTruck 类定义同上) ...public class ReactiveAggregationExample {    private OrderService orderService;    private VehicleService vehicleService;    public ReactiveAggregationExample(OrderService orderService, VehicleService vehicleService) {        this.orderService = orderService;        this.vehicleService = vehicleService;    }    public Mono getOrderAndTruck(UUID orderId) {        // 步骤1:获取原始Mono        Mono orderMono = orderService.getById(orderId);        // 步骤2:通过flatMap获取依赖Mono        // 注意:这里truckMono依赖于orderMono,所以必须在orderMono发出数据后才能创建        Mono truckMono = orderMono.flatMap(order -> vehicleService.getByTruckId(order.getTruckId()));        // 步骤3:使用Mono.zip聚合结果        // Mono.zip会等待两个Mono都发出数据,然后将它们包装成一个Tuple2        Mono<Tuple2> zippedMono = Mono.zip(orderMono, truckMono);        // 步骤4:将聚合结果转换为自定义对象        // 再次使用flatMap将Tuple2转换为OrderWithTruck        Mono resultMono = zippedMono.flatMap(tuple ->            Mono.just(new OrderWithTruck(tuple.getT1(), tuple.getT2()))        );        return resultMono;    }    public static void main(String[] args) {        // 模拟服务实现        OrderService mockOrderService = id -> Mono.just(new Order(id, "Order B", UUID.randomUUID()));        VehicleService mockVehicleService = truckId -> Mono.just(new Truck(truckId, "Mercedes-Benz Actros"));        ReactiveAggregationExample example = new ReactiveAggregationExample(mockOrderService, mockVehicleService);        UUID testOrderId = UUID.randomUUID();        example.getOrderAndTruck(testOrderId)               .subscribe(                   orderWithTruck -> System.out.println("成功聚合订单和卡车信息: " + orderWithTruck),                   error -> System.err.println("聚合信息失败: " + error.getMessage())               );        // 确保主线程不会立即退出        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            Thread.currentThread().interrupt();        }    }}

解析:

orderMono:这是第一个独立的响应式流,它会发出Order对象。truckMono:这个流的创建依赖于orderMono发出的Order对象。我们再次使用flatMap来确保当Order可用时,才触发vehicleService.getByTruckId调用。Mono.zip(orderMono, truckMono):zip操作符会等待所有作为参数传入的Mono都发出一个元素后,将这些元素打包成一个Tuple2(或Tuple3等,取决于参数数量)并发出。需要注意的是,尽管truckMono的创建依赖于orderMono,但zip操作符本身并不会改变这种依赖关系。它只是在两个Mono都完成后才聚合结果。zippedMono.flatMap(tuple -> Mono.just(new OrderWithTruck(tuple.getT1(), tuple.getT2()))):zip操作符返回的是一个Mono<Tuple2>。为了将其转换为我们自定义的OrderWithTruck类型,我们再次使用flatMap(或更简单的map,因为这里只是转换Tuple2为OrderWithTruck,而不是将Tuple2转换为一个新的Mono)。Mono.just()用于将一个普通对象包装成一个Mono。

注意事项与最佳实践

避免阻塞操作: 在响应式流中,严禁使用block()或toFuture().get()等阻塞操作。这会违背响应式编程的核心原则,并可能导致线程饥饿和性能问题。错误处理: 在链式调用中,任何一个Mono的错误都会向下传播。应使用onErrorResume、onErrorReturn、doOnError等操作符来优雅地处理错误,例如提供默认值、执行回退逻辑或记录错误。map vs flatMap:当你的转换函数返回一个普通对象时,使用map。例如:mono.map(item -> new TransformedItem(item))。当你的转换函数返回一个Publisher(如Mono或Flux)时,使用flatMap。flatMap会将这些内部的Publisher扁平化,使其发出的元素成为主流的元素。可读性: 复杂的链式操作可以通过方法抽取、局部变量来提高可读性。性能考量: Mono.zip通常用于需要并行执行多个不互相依赖的Mono,然后聚合结果的场景。在truckMono依赖于orderMono的场景下,zip的聚合能力依然有效,但truckMono的实际执行依然是顺序的(在orderMono完成后)。

总结

Project Reactor 提供了一套强大且灵活的工具集来处理异步和非阻塞的数据流。通过熟练运用flatMap和Mono.zip等核心操作符,开发者可以优雅地实现从Mono中提取字段并进行链式调用,无论是仅关注后续操作结果,还是需要聚合多个操作的结果。掌握这些模式对于构建高性能、可伸缩的响应式应用程序至关重要。始终记住,在响应式世界中,避免阻塞是黄金法则,而flatMap和zip是实现非阻塞链式操作的基石。

以上就是Project Reactor:从Mono中提取字段并进行非阻塞链式调用的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/740116.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
神马搜索如何优化搜索缓存_神马搜索缓存管理的实用方法
上一篇 2025年11月25日 14:45:33
怎么进行b站考试_参加B站相关考试(如创作入门等)的流程
下一篇 2025年11月25日 14:45:40

相关推荐

  • 如何解决Symfony项目中的OAuth认证问题?使用friendsofsymfony/oauth-server-bundle可以!

    可以通过以下地址学习Composer:学习地址 在开发symfony项目时,实现oauth认证常常是一个复杂且耗时的过程。最近我在一个项目中遇到了这个问题,尝试了多种方法后,始终无法顺利集成oauth认证。最终,我找到了friendsofsymfony/oauth-server-bundle这个bu…

    用户投稿 2026年8月28日
    000
  • win10电脑扬声器正常但是没有声音怎么回事

    win10电脑扬声器正常但是没有声音怎么回事win10电脑扬声器正常但是没有声音怎么回事win10电脑扬声器正常但是没有声音怎么回事win10电脑扬声器正常但是没有声音怎么回事

    想要在win10电脑上播放音乐或观看电影时却发现没有声音,虽然扬声器看起来正常却无法发声,这可能是由多种原因引起的。接下来,我们将介绍几种可能的解决办法。 工具/材料: 系统版本:Windows 10 设备类型:笔记本/台式机 解决步骤: 步骤一:排查驱动问题 首先,右键点击屏幕左下角的“开始”按钮…

    2026年8月28日 用户投稿
    000
  • 抖音怎么删除自己的作品?一键删除抖音全部作品

    越来越多的用户开始利用这款短视频平台记录日常生活、分享欢乐瞬间。然而,在使用抖音的过程中,大家可能会碰到一些令人困扰的情况,例如想清除某些内容却不知如何下手。本文将教你如何简单地移除自己的作品,让你能够自由自在地表达自我,无负担地分享精彩片段。 一、为何要清理作品 1. 维护隐私安全:在抖音上发布的…

    2026年8月28日
    000
  • windows怎么重启日志查看

    使用事件查看器中的事件ID 41、6005、6006和1074筛选系统日志,结合可靠性监视器与蓝屏分析工具,可准确区分正常重启与意外崩溃。 要查看Windows系统的重启日志,最直接且信息最丰富的途径就是使用“事件查看器”(Event Viewer)。它详细记录了系统启动、关机以及各种异常事件,是追…

    2026年8月28日
    000
  • Laravel 电商系统实战:商品管理+支付集成

    laravel 适合开发电商系统,因为它能快速搭建高效系统并提供艺术般的开发体验。1)商品管理通过 eloquent orm 实现 crud 操作和分类关联。2)支付集成通过 stripe api 处理支付请求和异常,确保支付流程的安全性和可靠性。 引言 搞电商系统,特别是用 Laravel 来搞,…

    2026年8月28日
    000
  • 抖音怎么看好友在不在线?抖音怎么看好友在不在线状态

    抖音已经成为现代人日常生活中不可或缺的一部分。通过这个平台,人们可以轻松地分享生活点滴并与好友互动。然而,许多人对于如何查看好友的在线状态感到困惑。本文将详细介绍如何在抖音上判断好友的在线状态,并提供一些实用技巧来提升与好友的互动频率。 一、抖音好友在线状态解析 1. 在线状态的判断机制 抖音依据多…

    2026年8月28日
    000
  • 黄仁勋:英伟达最后入局半导体但永远不晚,自己若今年毕业将爱上 AI

    7 月 16 日消息,根据新浪科技报道,英伟达 CEO 黄仁勋在今日下午的媒体采访中提到,英伟达是较晚成立的半导体公司之一,但他强调“入场虽晚,却从不嫌迟”。 黄仁勋说道:“我不是先行者,而是后来者,所以永远不会太晚。因为如果你是第一个进入市场的人,你有独特的优势;而作为最后一个进入的人,同样也能找…

    2026年8月28日
    100
  • ThinkPHP 性能优化:10个提升速度的技巧

    提升thinkphp应用性能的10个技巧包括:1.优化数据库查询,减少查询次数;2.使用缓存策略,降低数据库负载;3.实施延迟加载,减少初始加载时间;4.进行批量操作,减少数据库连接次数;5.避免n+1查询问题,使用关联查询;6.优化模板渲染,使用缓存模板;7.启用编译模式,提升启动速度;8.优化日…

    2026年8月28日
    100
  • 硬盘无法识别故障排查,数据恢复及预防技巧分享

    硬盘无法识别故障排查,数据恢复及预防技巧分享硬盘无法识别故障排查,数据恢复及预防技巧分享硬盘无法识别故障排查,数据恢复及预防技巧分享硬盘无法识别故障排查,数据恢复及预防技巧分享

    硬盘无法识别时,先排查电源和数据线连接是否正常,再依次检查bios设置、驱动程序、操作系统问题,若无效则可能是物理损坏;1.检查电源和数据线,尝试更换线材;2.进入bios查看硬盘是否被识别,确认启动模式正确;3.通过设备管理器检查并更新驱动;4.若硬盘有异响等物理损坏迹象,应停止使用并联系专业机构…

    2026年8月28日 用户投稿
    200
  • 如何解决Behat测试的代码覆盖率问题?dvdoug/behat-code-coverage助你提升测试质量

    可以通过一下地址学习composer:学习地址 在进行php应用程序开发时,测试是确保代码质量和功能正确性的关键步骤。behat作为一个行为驱动开发(bdd)工具,能够帮助我们编写和运行功能测试。然而,在使用behat进行测试时,我发现了一个显著的缺陷:它无法直接提供代码覆盖率报告。这意味着我们无法…

    用户投稿 2026年8月28日
    000
  • 快捷方式图标修复:如何恢复默认图标的完整教程 | 注册表修复与系统还原方案

    快捷方式图标变成白纸或通用图标,通常是由于图标缓存损坏、文件关联出错、程序卸载不彻底、病毒攻击或系统文件损坏所致;最有效的解决方法是先尝试重建图标缓存,通过删除%localappdata%目录下的iconcache.db文件并重启资源管理器或电脑,使系统重新生成缓存;若问题依旧,可检查快捷方式属性中…

    2026年8月28日
    000
  • 深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新

    深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新深度解析三星GalaxyZ Fold7的轻薄化设计与结构革新

    提到折叠屏手机,三星无疑是行业开拓者。自2008年开始探索折叠屏技术,到2011年推出首款原型机,再到2019年正式发布首款商用折叠屏设备galaxy fold,三星在该领域深耕超过15年,持续推动形态创新,逐步确立了其行业领先地位。如今,全新推出的galaxy z fold7,在轻薄化、性能与耐用…

    2026年8月28日 用户投稿
    000
  • Laravel 最佳扩展包推荐:2024 年必备工具

    2024年必备的laravel扩展包包括:1. laravel debugbar,用于监控和调试代码;2. laravel telescope,提供详细的应用监控;3. laravel horizon,管理redis队列任务。这些扩展包能提升开发效率和应用性能。 引言 在 Laravel 生态系统中…

    2026年8月28日
    100
  • 悟空浏览器如何设置打印网页时不带页眉页脚_悟空浏览器打印网页去掉页眉页脚方法

    在悟空浏览器中打印网页时,可通过打印预览设置取消页眉页脚:打开打印界面后展开更多设置并取消勾选“页眉和页脚”;2. 使用开发者工具添加CSS样式@media print { @page { margin: 0; } }可彻底去除页眉页脚及边距;3. 或将网页导出为PDF:选择虚拟PDF打印机并关闭页…

    2026年8月28日
    100
  • 别着急, 抖音500有效粉丝太贵了(看我把价格打下来)

    抖音有效粉丝是我们开展电商带货一个重要指标,平台设置有效粉丝门槛是为了更好规范市场,避免一些虚假账户和矩阵带货,可是也难住了很多渴望直播带货和短视频带货的普通人,大家在了解市场有效粉丝涨粉方式和价格以后,也在吐槽有效粉丝价格太贵了,为了能把有效粉丝价格打下来,经过小编多年抖音运营经验积累和实测数据反…

    2026年8月28日
    100
  • 如何解决从图像中提取颜色的问题?使用Composer可以轻松搞定!

    可以通过以下地址学习 Composer:学习地址 在处理图像处理项目时,我遇到了一个有趣但棘手的问题:如何从图像中提取颜色,并且提取的结果要尽可能接近人类的感知方式。尝试了多种方法后,我发现了一个名为 league/color-extractor 的库,它通过 composer 可以轻松安装并使用,…

    用户投稿 2026年8月28日
    100
  • 抖音推广怎么收费?抖音花100元推广有效果吗

    抖音作为当前主流的短视频平台之一,已成为众多品牌开展营销的重要阵地。关于抖音推广的费用问题,一直是企业主关注的重点。本文将从抖音推广的计费方式出发,分析其效果,并提供一些实用建议。 一、抖音推广的主要计费模式 1. 广告主付费机制 抖音广告投放主要采用以下几种计费方式: (1)CPM(每千次展示成本…

    2026年8月28日
    100
  • Laravel 队列(Queue)与任务调度:提升应用性能

    laravel 应用可以通过队列和任务调度提升性能。1) 队列用于异步处理耗时任务,提高响应速度。2) 任务调度用于自动执行定时任务,实现自动化操作。 引言 当你深陷于 Laravel 应用的开发中,性能问题总会如影随形。如何让你的应用在高并发下依然保持优雅的姿态?答案之一就是巧妙地利用 Larav…

    2026年8月28日
    100
  • ZXing生成二维码水印变黑白的原因及解决方法是什么?

    解决zxing生成二维码水印变黑白的问题 在使用ZXing库生成二维码并用Thumbnailator库添加水印时,常常遇到水印颜色变黑白的困扰。这是因为ZXing生成的二维码默认位深度为1(黑白),而水印图片通常是彩色图像。Thumbnailator在叠加水印时,会根据底图(二维码)的位深度调整输出…

    2026年8月28日
    100
  • 蝴蝶号如何制作美食视频 蝴蝶号垂直领域的创作指南

    明确美食视频定位,如家常菜、创意料理或探店测评,聚焦特定受众;2. 使用手机拍摄,确保光线充足、背景整洁,提升画面质感;3. 拍摄前撰写脚本,规划食材展示、烹饪步骤与试吃环节;4. 采用多角度、稳运镜、柔光线提升视觉效果;5. 剪辑时保持节奏紧凑,搭配合适音乐并添加清晰字幕;6. 内容上分享独家技巧…

    2026年8月28日
    100

发表回复

登录后才能评论
关注微信