领先一步
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 更改分为两类
重命名方法以更好地使 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
现在可以替换任何 Scheduler 的方式。最值得注意的是,当通过 StepVerifier#withVirtualTime
使用时,VTS 实际上将替换所有默认调度程序。
这意味着,如果您正在测试以前在例如 Schedulers.elastic()
中隔离的阻塞代码,现在需要在专用的 Scheduler
中进行测试,该 Scheduler
在 StepVerifier
之前创建(例如 Schedulers.newSingle()
)。
处理器已重新设计。尤其需要注意的是,您不再需要显式连接到某些处理器,而应始终使用新的 sink()
方法。这使所有处理器的 API 保持一致,并为那些本身未进行串行化的处理器进行串行化调用。整个 Processor
系列的使用现在更接近于 Flux.create
。
Scannable
接口替换了主要在内部使用并已被移除的内省接口(Loopback
、MultiProducer
、MultiReceiver
、Producer
、Receiver
、Trackable
)。
目标是支持序列的内省,包括通过遍历运算符,在一个接口中。从现在到 GA 版本发布,我们将更加关注使用这种机制的支持性。
为了延迟 `Mono` 的发射,直到伴随的 `Publisher` 完成之后,`delayUntil` 和 `delayUntilOther` 操作符被添加到 `Mono` 中。对于 `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` 可以包含重要的新的特性和破坏性更改,而 `MINOR` 在同一个 `MAJOR` 版本内都是二进制和 API 兼容的(尽管它们除了错误修复之外,还可以包含内部更改和新特性)。