Reactor Bismuth 版本列首个里程碑可用

版本发布 | Simon Baslé | 2017 年 5 月 16 日 | ...

我谨代表 Reactor 团队荣幸地宣布,Reactor 上周达成了一个重要的里程碑,使 Bismuth-M1 版本列可用。

这个首个里程碑版本支持新发布的 Spring Framework 5 RC1。它特别包含了 reactor-corereactor-testreactor-extra3.1.0.M1 版本。

由于 3.1.x 系列将成为长期支持分支(这对于支持 Spring 框架的版本来说是合适的),重点一直放在稳定和完善 API 上。因此,预计与 3.0.x 版本相比会有一些重大变更 [1]。

从 3.0.x 迁移

如果您在 3.0.x 阶段一直保持您的 Reactor 依赖项是最新的(意味着您使用的是 reactor-core 3.0.7),那么您应该注意到在最近几个版本中有些方法已被标记为废弃。

我们已尽力通过提前提供新的 API,并在方法重命名的情况下,在新方法引入时废弃旧方法,为迁移到 3.1.0 铺平道路。

这些在 3.0.x 中已废弃的方法大部分已在 3.1.0.M1 中移除,所以在更新您的依赖项之前,请务必遵循这份快速迁移指南!

在极少数情况下,此策略无法应用,我们将在下面详细介绍这些情况的迁移模式。

寻找废弃方法

对于大多数 API 变更,在 3.0.7 中都存在废弃说明,因此开始迁移的最简单方法是在代码中查找废弃的 API 使用,并根据 javadoc 中的建议进行修复。

大多数 API 变更分为两类

  1. 重命名方法以更好地对齐 FluxMono 之间的 API消除 lambda 使用的一些歧义:新别名将在 3.0.7 中引入,旧方法将被废弃,并附有使用新别名的说明。

  2. 移除冗余的运算符变体,例如所有 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);

但是 Mono 中已经存在 flatMap,其签名如下

Flux<V> flatMap(Function<T, Flux<V>> mapFunction)

由于 flatMap 通常返回与封闭类型相同的类型,因此将then(Function) 重命名为 flatMap,并将旧的 flatMap 更改为 flatMapMany(遵循已建立的后缀约定,表示 Mono 被此类操作符转换为 Flux)似乎更正确。

由于无法在 3.0.x 中引入仅返回类型不同的新 flatMap 签名(我们在该版本中只想废弃旧的 flatMap),因此这种迁移更难预料。

因此,最佳的迁移“秘诀”是

  1. 首先将所有 Mono.flatMap 的用法替换为 flatMapMany

  2. 完成其他重构和迁移

  3. 切换到 3.1.0.M1

  4. 将所有 Mono.then(Function) 的用法(现在无法编译)替换为 flatMap

注意

请注意,如果您不执行步骤 1,您可能会收到具有误导性的编译错误:包含 flatMap 的序列原本会继续作为 Flux,但现在将继续作为 Mono
如果在操作符链的下游您依赖于它是 Flux(例如,使用仅此类型可用的操作符,如 reduce()),编译错误就会出现在下游。
与其直接解决编译错误,您需要注意到代码期望的是 Flux,这是因为上游没有使用 flatMapMany…​

调度器(Schedulers)、时间和虚拟时间测试

Schedulers.timer() 调度器已被移除,所有默认调度器现在都能够提交具有延迟/周期性的任务。因此,对于像 delay() 这样的操作符,默认的 Scheduler 现在是 Schedulers.parallel()。请注意,线程名称现在将遵循 "parallel-`x`" 模式,其中 x 在工作线程数之间变化,而不是单一的 "timed-`n`"

另一个变化是 reactor-test 中的 VirtualTimeScheduler 现在可以替换任何 Scheduler。最值得注意的是,当通过 StepVerifier#withVirtualTime 使用时,VTS 将确实替换所有默认 Scheduler

这意味着如果您正在测试阻塞代码,而您以前会将其隔离在例如 Schedulers.elastic() 中,现在您需要在 StepVerifier 之前创建一个专用的 Scheduler(例如 Schedulers.newSingle())来执行此操作。

Processor 变更

Processors 已被重做。值得注意的是,您不再需要显式连接到某些 Processor,而应该始终使用新的 sink() 方法。这将所有 Processor 的 API 对齐,并为那些本身未序列化的调用进行序列化。整个 Processor 系列的使用现在更接近于 Flux.create

新特性

Scannable

Scannable 接口取代了主要用于内部并已被移除的自省接口(LoopbackMultiProducerMultiReceiverProducerReceiverTrackable)。

目标是在一个接口中支持序列的自省,包括遍历操作符。从现在到 GA 版本发布之前,将越来越注重使用此机制来提高可支持性。

Mono.delayUntil

delayUntildelayUntilOther 操作符已添加到 Mono 中,以便将 Mono 的发射延迟到一个配套的 Publisher 完成之后。对于 delayUntil,该配套 Publisher 是由源 Mono 发射的值生成的。然而,延迟 Publisher 的触发是在源完成时进行的。这与最近添加的 untilOther 非常相似,只是后者是在 onNext 而非 onComplete 时触发其配套 Publisher。

关于是否应废弃 untilOther 的决定仍在讨论中,因为我们认为它的名称及其依赖 onNext 的行为表达性较低,实用性也较差。

结论

最后,我要向参与最新 3.0.x 版本以及 M1 版本的社区贡献者致敬(github 用户名按字母顺序排列):@bdavisx @Dmitriusan @garyrussell @lebannen @lhotari @madhead @nebhale @rajinisivaram @RunninglVlan @sdeleuze @schauder

再次感谢大家!

要获取此版本,请将 BOM 与 Spring Milestone 仓库一起使用(参见参考指南此处)。

最后,一个行动号召

如果您对此里程碑有任何疑问,或者更重要的是有任何意见或建议,请随时加入 Gitter 上的实时讨论或提交一个 Issue

响应式编程快乐!


1. 提醒一下,Reactor 3 并不完全遵循语义版本控制的 MAJOR.MINOR.PATCH 方案,而是遵循 X.MAJOR.MINOR 版本控制方案X 增加意味着重大的架构和 API 重做,MAJOR 可以包含重要的新特性和重大变更,而同一 MAJOR 内的 MINOR 版本在二进制和 API 上都兼容(尽管它们除了 Bug 修复外还可以包含内部更改和新特性)

订阅 Spring 通讯

订阅 Spring 通讯,保持联系

订阅

领先一步

VMware 提供培训和认证,助您快速前进。

了解更多

获取支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,仅需一次简单订阅。

了解更多

近期活动

查看 Spring 社区的所有近期活动。

查看全部