领先一步
VMware 提供培训和认证,助您加速进步。
了解更多我谨代表 Reactor 团队,很高兴地宣布 Reactor 上周**达到了一个重要的里程碑**,发布了 Bismuth-M1 发布火车。
这个第一个里程碑支持新发布的 Spring Framework 5 RC1。它特别包含了 reactor-core、reactor-test 和 reactor-extra 的 3.1.0.M1 版本。
由于 3.1.x 版本系列是长期支持分支(正如支持 Spring framework 的版本一样),因此重点放在稳定和打磨 API 上。因此,预计与 3.0.x 版本相比会有一些重大更改 [1]。
如果您在 3.0.x 版本阶段一直保持 Reactor 依赖项的更新(这意味着您使用的是 reactor-core 3.0.7),那么您会注意到最近几个版本中出现了一些被弃用的方法。
我们已尽力为 3.1.0 版本做好准备,提前提供新 API,并在方法重命名的情况下,在新方法引入时弃用旧方法。
在 3.0.x 版本中被弃用的方法,在 3.1.0.M1 版本中大多已被移除,因此在更新您的依赖项之前,请务必遵循本快速迁移指南!
在极少数情况下,此策略无法应用,我们将在下面详细介绍这些迁移模式。
大部分 API 更改在 3.0.7 中都有弃用说明,因此开始迁移的最简单方法是查找代码中被弃用的 API 用法,并根据 javadoc 中的建议进行修复。
大多数 API 更改属于以下 2 类:
重命名方法以更好地对齐 Flux 和 Mono 之间的 API 或消除 lambda 使用中的歧义:新别名将在 3.0.7 中引入,旧方法将被弃用并附带使用新别名的提示。
移除操作符的冗余变体,例如所有 xxxMillis 变体(这些变体已被移除,以支持仅使用基于 Duration 的替代方法):方法将被弃用,并附带使用保留的变体的提示。
但也存在一个更棘手的情况
Mono.then(Function) 和 Mono.flatMap与其他 then 变体不同,它们的效果是忽略 Mono 的数据,然后在完成时用另一个 Publisher 继续执行,Mono.then(Function) 会在 onNext 事件上做出反应。
这违反了最小惊喜原则,并且在链式调用多个 then 时可能导致意外行为。请看这个例子:
Mono.just(someObject)
.thenEmpty(Mono.fromRunnable(AsyncUtils::runDiagnostics))
.then(v -> AsyncUtils.toJson(v));
这段代码永远不会调用 runCleanupFor,因为前面的 thenEmpty 返回一个 Mono<Void>。但是,如果 Function 中使用的代码能够使用 Void 泛型类型进行编译,那么您将不会收到任何警告。
进一步查看签名以及该操作符不像其其他变体那样完全忽略 onNext 信号的事实,我们注意到这实际上更接近经典的 flatMap。
Mono<V> then(Function<T, Mono<V>> thenFunction);
但是 flatMap 已经在 Mono 中存在,签名如下:
Flux<V> flatMap(Function<T, Flux<V>> mapFunction)
由于 flatMap 通常返回与封闭类型相同的类型,因此将 then(Function) 重命名为 flatMap,并将旧的 flatMap 改为 flatMapMany(遵循已建立的后缀约定,该约定指示 Mono 被此类操作符转换为 Flux)似乎更正确。
由于不能在 3.0.x 中引入仅通过返回类型不同的新 flatMap 签名(当时我们只想弃用旧的 flatMap),因此此迁移更难预料。
因此,最佳迁移“秘诀”是:
首先将所有 Mono.flatMap 的用法替换为 flatMapMany。
完成其他重构和迁移。
切换到 3.1.0.M1。
然后将所有 Mono.then(Function) 的用法(现在无法编译)替换为 flatMap。
注意
请注意,如果您不执行步骤 1,可能会遇到误导性的编译错误:包含 flatMap 的序列以前会继续作为 Flux,而现在会继续作为 Mono。
如果在操作符链的下游,您依赖于处于 Flux 状态(例如,使用仅在此类型上可用的操作符,如 reduce()),编译错误将在稍后出现。
与其从表面上修复编译错误,您需要注意到代码期望的是 Flux,而这是由于上游没有使用 flatMapMany……
Schedulers.timer() 调度器已被移除,所有默认调度器现在都能提交带有延迟/周期性的任务。因此,对于 delay() 等操作符,默认的 Scheduler 现在是 Schedulers.parallel()。请注意,线程名称现在将遵循 "parallel-`x`" 模式,其中 x 在工作线程数之间变化,而不是单个 "timed-`n`"。
另一个变化是 reactor-test 中的 VirtualTimeScheduler 现在可以替换任何调度器。最值得注意的是,当通过 StepVerifier#withVirtualTime 使用时,VTS 将替换所有默认调度器。
这意味着,如果您正在测试之前隔离在例如 Schedulers.elastic() 中的阻塞代码,现在您需要在 StepVerifier之前创建的专用 Scheduler 中执行此操作(例如 Schedulers.newSingle())。
处理器已重构。特别是,您不再需要显式连接到某些处理器,而是应始终使用新的 sink() 方法。这统一了所有处理器的 API,并序列化了那些尚未固有序列化的调用。整个 Processor 系列的使用现在更接近 Flux.create。
Scannable 接口取代了主要是内部使用的省去内省接口,这些接口已被移除(Loopback、MultiProducer、MultiReceiver、Producer、Receiver、Trackable)。
目标是使用单个接口支持序列的内省,包括通过遍历操作符。从现在到 GA 发布,将增加对此机制的支持。
delayUntil 和 delayUntilOther 操作符已添加到 Mono 中,以延迟 Mono 的发射,直到一个伴随的 Publisher 完成。对于 delayUntil,该伴随由源 Mono 发射的值生成。但是,延迟 Publisher 的触发是在源完成时进行的。这非常接近最近添加的 untilOther,除了后者在 onNext 时触发其伴随,而不是在 onComplete 时触发。
关于 untilOther 是否应该被弃用,目前仍在等待决定,因为我们认为其名称和依赖于 onNext 的行为都不够清晰和有用。
最后,我要特别感谢参与最新的 3.0.x 版本和 M1 版本社区贡献者(GitHub 用户名按字母顺序排列):@bdavisx @Dmitriusan @garyrussell @lebannen @lhotari @madhead @nebhale @rajinisivaram @RunninglVlan @sdeleuze @schauder。
再次感谢大家!
要获取此版本,请使用 BOM 和 Spring Milestone 存储库(请参阅 此处的参考指南)。
最后,一个行动呼吁:
如果您对这个里程碑有任何疑问,或者更重要的是任何意见或建议,请随时在 Gitter 上加入实时讨论 Gitter 或 打开一个 issue。
祝您编程愉快!
1. 提醒一下,Reactor 3 并非完全符合语义化版本控制的 MAJOR.MINOR.PATCH 方案,而是遵循 X.MAJOR.MINOR 版本方案。X 的递增意味着重大的架构和 API 重做,MAJOR 可以包含重要的功能和破坏性更改,而 MINOR 在同一个 MAJOR 内是二进制和 API 兼容的(尽管它们可以包含内部更改和新功能以及错误修复)。