领先一步
VMware 提供培训和认证,助您加速进步。
了解更多经过 一年多的努力、多个重要里程碑以及基于大量反馈进行的微调,我很高兴宣布 Reactor 3 正式发布(General Availability)。您可以在 Maven Central 上找到 Reactor Core 3.0.2.RELEASE。
Reactor 3 为基于 Java 8 的应用提供了一个强大而高效的响应式编程模型。该模型借鉴了 Reactor 2 和 RxJava 1 的经验,并引入了一种流畅的方式来组合异步且支持背压的事件处理。Spring Framework 5 使用 Reactor 3 来构建并最终展示一个完整的响应式故事。
其设计依赖于一个可扩展的执行模型,该模型倾向于将事件处理安排在同一位置(colocation)。通常,Reactor 只会在明确要求时才在事件流阶段之间切换线程。例如,内存操作(如列表访问或负载转换)通常不需要跨越线程边界。如果操作的生产者或消费者可能耗时,用户应使用 Flux#publishOn
/ Mono#publishOn
或 Flux#subscribeOn
/ Mono#subscribeOn
来操作其流,并选择一个调度器(Scheduler)来运行。另外,如果用户像使用 merge 或 concat 那样组合多个 Publisher
的结果,Reactor 将隐式地以线程安全的方式处理各种潜在的线程边界。实际上,由 Publisher
托管的流阶段至少可能被一个生产线程和一个消费线程遍历。
所有这些都按照 Reactive Streams 规范定义的行为实现。Reactor 致力于使该规范成为库作者或 Spring 开发者们的便利工具,提供了在流处理或异步场景中应用的预制操作符。
流定义(flow definition)是 Reactor 称呼的一种链式结构,取决于流入已定义流的数据量,它可能是 Flux 或 Mono。这些类型在每个阶段都实现了 Reactive Streams 的 Publisher
接口,并且可以泛型地传递。那么为什么需要 两种 响应式类型呢?因为数量基数(cardinality)对 Reactor 很重要。一个 Flux
将观察 0 到 N 个项目,并最终成功或失败地终止。一个 Mono
将观察 0 或 1 个项目,而 Mono<Void>
则表示最多 0 个项目。
让我们看看以下阻塞 API
interface BlockingUserRepository {
User get(String id);
List<User> findAll();
void save(User data) throws RepositoryException;
List<User> findAllByUsernameLike(String s);
}
使用普通的 Reactive Streams Publisher
,我们将得到以下契约
interface ReactiveUserRepository {
Publisher<User> get(String id);
Publisher<User> findAll();
Publisher<Void> save(Publisher<? extends User> source);
Publisher<User> findAllByUsernameLike(String s);
}
但使用 Reactor,我们可以保留预期数量基数的语义证据
interface ReactorUserRepository {
Mono<User> get(String id);
Flux<User> findAll();
Mono<Void> save(Publisher<? extends User> source);
Flux<User> findAllByUsernameLike(String s);
}
由于 Mono
和 Flux
都实现了 Publisher
接口,我们可以轻松地将它们的任何引用作为响应式数据源传递,同时使用 Mono<Void>
流畅 API 返回明确的语义
// ReactorUserRepository userRepository;
userRepository.save(Mono.fromCallable(() -> new User("thomas")))
.doOnSuccess(res -> success())
.subscribe();
userRepository.save(Flux.just(new User("bob"), new User("robert")))
.doOnSuccess(res -> success())
.subscribe();
请记住,Flux
和 Mono
适用于可能耗时的数据生产者。为了管理重入(reentrance)和线程安全,操作符有时必须在执行流中增加一些开销。尽管如此,效率仍然是核心关注点,我们收到了引擎贡献者 David Karnok 的定期报告。Reactor 3 目前是 JVM 上最高效的响应式库之一。除了这些直接相关的基准测试外,我们现在也受益于 RxJava 2 社区的反馈,因为它在概念上源于同一个核心:Reactive Streams Commons。
我们正在努力在接下来的几周内推出 3.0.3 版本,并且与 Spring 5、CloudFoundry 的最新需求以及 Reactive Streams Commons 的最新研究保持同步。
优先处理:
新的测试支持:Reactor 3 原计划包含测试支持,但初步反馈提出了一些用户体验问题。我们现在正在努力提供这部分缺失的功能。在此期间,用户可以轻松地从我们的测试中复制独立的 TestSubscriber 以满足他们的需求。
指导:虽然 Reactor 3 越来越受欢迎,但我们仍在进行大量的内部或外部人工互动,包括与具备 Rx 知识的高级用户以及由 Sebastien Deleuze 贡献的快速教程。您可以在本文末尾找到更多资源,但我们已经开始建立一些端到端场景,这些场景我们认为具体且有价值,并将有助于形成官方的 Reactor 参考指南。
IPC 是 Inter-Process Communication(进程间通信)的缩写,而 Reactor IPC 是一个持续进行的倡议,旨在回答“如何以 Reactive Streams 方式脱离 JVM”的问题。我们正在开发一套初步的实现,包括 Reactor Kafka、Reactor Aeron 和 Reactor Netty。实际上,目前正在进行大量的契约重新设计以及 Reactor Kafka/Netty 的工作,这些工作支持一些新的 Spring 响应式故事。IPC 计划的目的是不创建新的 Web 或消息传递框架,而是构建应用程序或库可以基于的响应式驱动程序。它们将给定的运行时输入/输出转换为 Flux
和 Mono
或 Subscriber
,将响应式背压一直传播到 IO 访问层。预计未来几个月会有很多关于这些计划的新闻。
让我们花一些时间向此次发布的幕后贡献者致谢。David Karnok 是新 Reactor 引擎的主要架构师,并领导着 Reactive Streams Commons 的研究工作。Spring、Eclipse STS 和 CloudFoundry Client 团队也在设计改进和反馈方面做出了重要贡献。除了 Pivotal,MuleSoft 在最新开发方面也提供了巨大的帮助并保持积极主动。
RxJava 1 将主流响应式带到了 JVM,其完整的函数式 Rx 代数已成为一个行业标准,我们正与此保持一致。它启发了我们通过 Reactive Streams 实现的颠覆性规范,并将 Netflix、Oracle、Pivotal、Typesafe、Red Hat 等众多 JVM 关键参与者汇聚在一起。
敬请关注更多响应式故事!Reactor 在 Pivotal 的旅程才刚刚开始,经过过去几年的大量努力和研究,我们很高兴能带来全新的体验。我们的价值主张与 Spring OSS 直接相关,我们拥有独特的机会,可以在整个 Spring 产品组合中以端到端的方式交付响应式管道。
最后,Spring 和 Reactor 感谢我们的社区,感谢你们给予的巨大支持、鼓励和反馈。我们多年来建立的反馈循环不仅仅是一种良好的务实协作,更是我们所有人逐步改变这个行业所需要的。