领先一步
VMware 提供培训和认证,助您快速前进。
了解更多我谨代表 Reactor 团队荣幸地宣布,Reactor 上周达成了一个重要的里程碑,使 Bismuth-M1
版本列可用。
这个首个里程碑版本支持新发布的 Spring Framework 5 RC1。它特别包含了 reactor-core
、reactor-test
和 reactor-extra
的 3.1.0.M1
版本。
由于 3.1.x 系列将成为长期支持分支(这对于支持 Spring 框架的版本来说是合适的),重点一直放在稳定和完善 API 上。因此,预计与 3.0.x 版本相比会有一些重大变更 [1]。
如果您在 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 变更分为两类
重命名方法以更好地对齐 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);
但是 Mono
中已经存在 flatMap
,其签名如下
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 将确实替换所有默认 Scheduler。
这意味着如果您正在测试阻塞代码,而您以前会将其隔离在例如 Schedulers.elastic()
中,现在您需要在 StepVerifier
之前创建一个专用的 Scheduler
(例如 Schedulers.newSingle()
)来执行此操作。
Processors 已被重做。值得注意的是,您不再需要显式连接到某些 Processor,而应该始终使用新的 sink()
方法。这将所有 Processor 的 API 对齐,并为那些本身未序列化的调用进行序列化。整个 Processor
系列的使用现在更接近于 Flux.create
。
Scannable
接口取代了主要用于内部并已被移除的自省接口(Loopback
、MultiProducer
、MultiReceiver
、Producer
、Receiver
、Trackable
)。
目标是在一个接口中支持序列的自省,包括遍历操作符。从现在到 GA 版本发布之前,将越来越注重使用此机制来提高可支持性。
delayUntil
和 delayUntilOther
操作符已添加到 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 修复外还可以包含内部更改和新特性)