当前位置: 首页 > 知识库问答 >
问题:

在ProjectReactor或akka streams中,接收器和用户之间的概念区别是什么?

公西俊民
2023-03-14

接收器和订户的概念对我来说似乎很相似。此外,我没有看到在反应流规范中明确定义sink的概念。

共有1个答案

戚研
2023-03-14

我看到ProjectReactor(缺少免责声明)的Oleh Dokuka已经给出了答案,但其关于Akka流和反应流的许多假设是不正确的,因此请允许我在下面澄清。

声明:我从早期就参与了Reactive Streams,并编写了它的大部分技术兼容性工具包。我也维护阿卡和阿卡流。

另请注意:Reactive Streams已包含在Java9中,并且被称为java.util.concurrent.Flow.*,因此下面所有关于RS的评论对j.u.c.Flow.Subscriber和其他类型的看法完全相同。

反应流,特别是发布者/订户/订阅/处理器类型,是服务提供商接口。这一点甚至在2014年关于该规范的最早讨论中也得到了证实。

在规范的早期,甚至规范的类型都试图隐藏发布者、订阅者和其他类型。可悲的是,这些类型会泄漏,不管在当时被认为是API,因此API(!)被移除,只剩下SPI类型。

现在,您可以看到一些反应流的实现声称,出于某种原因,它们对这些类型的直接扩展是一种好处。这是不正确的,因为它不是,也不是反应流接口的目标。这是对这些类型的误解——严格来说,是反应流库同意理解和“说话”(协议)的互操作接口。

作为参考,RxJava 2.0和Reacter确实直接扩展了这些类型,而Akka Streams仍然忠于RS的设计和原则,将它们隐藏为应用程序开发人员编程接口 - 这就是为什么Sink不扩展订阅者的原因。这与“原生支持”无关,我见过人们如何声称直接的IS-A关系是(相反,声称一个inter-op库是你的“原生”是对这个概念的误解)。

sink 和 subscriber 的概念似乎与我相似。

正确,它们在目的和设计上是相似的。

因为接收器是有效地产生订户的事物的提升表示。为了简化,您可以将其视为“订户工厂”(更具体地说,接收器是“蓝图”并且物化器获取接收器的蓝图并创建适当的RS阶段,包括源的发布者和接收器的订户。所以当你说水槽的时候。忽略它实际上是一个工厂,它最终将创建一个订户,该订户执行所有请求和忽略操作,根据反应流。在Sink上声明的所有其他方法也是如此。

这同样适用于,它与反应流发布服务器的关系为 1:1。因此,Source.single(1) 是一种将在内部实现为发布者的东西,该发布者可以完成其工作 - 如果它下游允许这样做,则发出该 1 元素。

如上所述,Akka的接收器不直接扩展订户。然而,它基本上是他们的工厂。

您可能会问:“在正常使用期间,用户是否根本看不到这些发布者/订阅者类型?”答案是:确实是,这是一个功能和设计目标(根据Reactive Streams是什么)。如果底层的发布者和订阅者实例一直直接暴露给用户,人们可能会错误地调用它们,从而导致错误和混淆。如果除非明确要求,否则这些类型永远不会暴露,那么意外错误的机会就会减少!

有些人误解了该设计,并声称Akka Streams中没有对其的“原生”支持(这不是真的)。让我们看看在API中与订阅者分离会给我们带来什么:

另外,我没有看到在反应流规范中明确定义接收器的概念。

事实上,汇不是反应流的一部分,这绝对没问题。

Sinks是Akka Streams的一部分,其目的是提供流畅的DSL,以及成为订户的工厂。换句话说,如果用户是乐高积木,Sink是构建它们的工具(而Akka流物化器,是将各种乐高积木块放在一起以“运行”它们的工具)。

事实上,Sink不像其他库那样携带任何带有订阅者(原文如此!)的最终IS-A对用户是有益的:

这是因为由于 org.reactivestreams.Subscriber 现在已经包含在 Java 9 中,并且已经成为 Java 本身的一部分,因此库应该迁移到使用 java.util.concurrent.Flow.Subscriber 而不是 org.reactivestreams.Subscriber。选择公开和直接扩展反应式流类型的库现在将更难适应JDK9类型 - 所有扩展订阅者和朋友的类都需要复制或更改以扩展完全相同的接口,但来自不同的包。在 Akka 中,我们只需在被要求时公开新类型 - 从 JDK9 发布之日起就已经支持 JDK9 类型。

反应流是一个SPI——一个服务提供者接口——它旨在让库共享,这样它们可以“使用相同的类型和协议”。Akka流所做的所有通信,以及其他反应流库所做的,都遵循那些规则,如果你想将其他一些库连接到Akka流,你可以这样做——给Akka流inter-op类型,即订户、处理器或发布者;不是水槽,因为那是Akka的“特定于Akka”的DSL(特定于域的语言),它增加了便利性和其他细节,隐藏了(故意的!)订户类型。

Akka(说实话,其他RS实现也被鼓励这样做,但选择不这样做)隐藏这些类型的另一个原因是因为它们很容易做错事。如果您传递订阅服务器,任何人都可以在其上调用内容,甚至无意中违反规则并保证反应流规范要求与该类型交互的任何人。

为了避免错误发生,Akka Streams中的Reactive Streams类型是“隐藏的”,并且仅在明确要求时才暴露 - 最大限度地降低了人们在不遵循其协议的情况下意外调用“原始”Reactive Streams类型上的方法而犯错误的风险。

 类似资料:
  • 我对面向对象编程有这种困惑。对于我编写的一些代码,我必须回答一些问题: 此代码中使用的OOP原则是什么 它们是如何应用的 解释此代码中使用的OOP概念 在这里,我不理解这两个词“原则”和“概念”之间的区别。它们是一样的吗?还是不同? 我知道有4个面向对象的原则。 继承权 在我的代码中,我有setter方法、getter方法、抽象类、类之间的继承。所以我的回答是: > 继承,抽象,封装,多态性。 我

  • 我知道还有其他类似的线程,但我不确定它们是否与Postgres相关。 我正在阅读PostgreSQL文档,内容如下: 注意:如第20章所述,PostgreSQL实际上在“角色”方面进行了权限管理。在本章中,我们始终使用数据库用户来表示“具有 LOGIN 特权的角色”。 这是否意味着角色是数据库用户?或者角色和用户之间有区别吗?用户是否有可能不具有完全权限,而角色是始终具有完全权限的用户?

  • 我是博士后新手,有一些问题。我在我的linux系统上安装了postgresql,它在系统上创建了一个用户postgres,我在pgadmin中也有一个postgres用户,他们是同一个用户吗? 我对jboss有问题,连接数据源会导致密码验证问题。 pg_hba。形态: 例外情况: 由以下原因引起:org.postgresql.util.PSQL异常:FATAL:org.postgresql.cor

  • 我试图了解两者之间是否有任何重大差异。在查看示例时,我注意到它使用了完全相同的二进制和arg(https://github.com/open-telemetry/opentelemetry-collector/blob/main/examples/demo/docker-compose.yaml). 唯一的区别是配置文件在导出器/接收器方面有所不同。因此,唯一的区别是使用什么endpoint来收集