接收器和订户的概念似乎与我相似。另外,我看不到反应流规范中明确定义了接收器的概念。
最佳答案
我从Project Reactor(在那里缺少免责声明)中发现Oleh Dokuka,已经是posted an answer,但是它对Akka Streams和Reactive Streams的许多假设都是不正确的,因此请允许我在下面进行说明。
免责声明:从早期开始,我就参与了Reactive Streams,并且参与了authored的大部分Technology Compatibility Kit。我还维护Akka和Akka Streams。
还要注意:Java 9中已经包含了响应式流,它们被称为java.util.concurrent.Flow.*,因此以下有关RS的所有注释与j.u.c.Flow.Subscriber
和其他类型完全一样。
答案
反应性流是服务提供商接口(interface)(SPI)规范
反应性流,特别是发布者/订阅者/订阅/处理器类型,是Service Provider Interface。即使在有关2014年规范的earliest discussions中也确认了这一点。
在规范的早期,甚至规范的类型都试图隐藏Publisher,Subscriber和其他类型。遗憾的是,无论在后面考虑的API thus the API(!) was removed and the SPI types are all that remained中,这些类型都会泄漏。
如今,您看到响应式流的一些实现声称由于某些原因,它们对这些类型的直接扩展是有好处的。事实并非如此,这是不正确的,也不是Reactive Streams接口(interface)的目标。确切地说,这些类型是什么的误解-严格来说,Reactive Streams库同意理解并“讲话”(一种协议(protocol))的互操作接口(interface)。
作为引用,RxJava 2.0和Reactor确实直接扩展了这些类型,而Akka Streams通过将它们隐藏为应用程序开发人员编程接口(interface)而忠实于RS的设计和原理-这就是Sink不扩展Subscriber的原因。这与“原生支持”无关,我已经看到人们声称直接的IS-A关系是(相反,声称互操作库是您的“原生”是对该概念的误解)。
接收者和订阅者,来源和发布者
正确,它们在故意和故意方面是相似的。
作为接收器,是有效产生订户的某种事物的lifted representation。为简化起见,您可以将其视为“订户工厂”(更具体地说,接收器是“蓝图”,而Materializer则采用接收器的蓝图并创建适当的RS阶段,包括源发布者和接收器订阅者。
因此,当您说Sink.ignore时,实际上它是一个工厂,最终将创建一个Subscriber来完成所有请求和忽略,如Reactive Streams所述。与在Sink上声明的所有其他方法相同。
这同样适用于Source
,它与1:1的Reactive Streams Publisher
相关。因此,Source.single(1)
是一种将在内部实现为自己工作的Publisher
的东西-如果下游允许,则发出1元素。
A.K.A.为什么反应流中没有接收器?
如上所述,Akka的接收器不会直接扩展订户。但是,基本上,这是他们的工厂。
您可能会问:“尽管在正常使用期间,用户是否根本看不到这些发布者/订阅者类型?”答案是:是的,的确如此,这既是功能也是设计目标(根据反应式流是什么)。如果底层的发布者和订阅者实例始终一直暴露给用户,则可能会错误地调用它们,从而导致错误和困惑。如果除非明确要求,否则绝不公开这些类型,那么发生意外错误的机会就更少!
一些人误解了该设计,并声称Akka Streams中没有“本机”支持(这是不正确的)。让我们来看看通过API与订阅服务器分离所获得的 yield :
的确,接收器不是反应流的一部分,那绝对没问题。
避免使用“接收器IS-A订户”的好处Sink
是Akka Streams的一部分,其目的是提供流畅的DSL,并且是Subscribers
的工厂。换句话说,如果订户是LEGO块,则Sink
是构建它们的源(而Akka Stream Materializer
是将各种LEGO块组合在一起以“运行”它们的源)。
实际上,与其他库一样,Sink不会随订户(sic!)一起携带任何确定的IS-A对用户来说是的优势:
这是因为因为org.reactivestreams.Subscriber
现在已包含在Java 9中,并且已经成为Java本身的一部分,所以库应该迁移到使用java.util.concurrent.Flow.Subscriber
而不是org.reactivestreams.Subscriber
。选择公开和直接扩展Reactive Streams类型的库现在将更难适应JDK9类型-他们所有扩展Subscriber和Friends的类都需要复制或更改以扩展完全相同的接口(interface),但是从不同的包装。在Akka中,我们仅在要求时公开新类型-从JDK9发布之日起就已经支持JDK9类型。
由于反应式流是SPI(服务提供者接口(interface))的SPI,旨在使库共享,以便它们可以“交谈相同的类型和协议(protocol)”。 Akka Streams和其他Reactive Streams库所做的所有通信都遵循这些规则,如果您要将其他库连接到Akka Streams,则只需这样做-为Akka Streams提供互操作类型,即是订阅者,处理器或发布者;而不是接收器,因为那是Akka的“Akka特定” DSL(域特定语言),它在其之上增加了便利性和其他优点,隐藏(故意!)订户类型。
Akka(也鼓励其他RS实现也这样做,但选择不这样做)隐藏这些类型的另一个原因是因为它们很容易用错误的方式做事。 如果您传递了订阅服务器,则任何人都可以调用它,甚至可以从与该类型进行交互的任何人那里调用un-knowingly break rules and guarantees that the Reactive Streams Specification requires。
为了避免发生错误,Akka Streams中的Reactive Streams类型是“隐藏的”,并且仅在明确要求时才公开-通过不遵循协议(protocol)的情况而意外地对“原始” Reactive Streams类型调用方法来最大程度地降低人们犯错的风险。
关于akka-stream - 在项目 react 堆或Akka流中,汇和订户之间的概念区别是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48162502/