响应式编程_05 Project Reactor 框架

文章目录

  • 概述
  • 响应式流的主流实现框架
    • RxJava
    • Reactor
  • Project Reactor 框架
    • Reactor 异步数据序列
    • Flux 和 Mono 组件
      • Flux
      • Mono
    • 操作符
    • 背压处理
  • 小结

在这里插入图片描述


概述

响应式编程_02基本概念:背压机制 Backpressure介绍了响应式流规范以及 Spring 框架中的响应式编程技术,也提到了响应式编程框架 Project Reactor。Reactor 是响应式领域中具有代表性的类库,实现了响应式流规范,同时已经成为 Spring 框架生态系统的重要组成部分。


响应式流的主流实现框架

如响应式编程_02基本概念:背压机制 Backpressure中所介绍的 在 Java 领域,目前响应式流的开发库包括 RxJava、Akka、Vert.x 和 Project Reactor 等。这里重点对 RxJava 和 Project Reactor 进行展开描述。

RxJava

说起 RxJava,我们先来讨论它的前缀 Rx。这里的 Rx 代表的是响应式扩展 Reactive Extensions,实际上它最早诞生于微软的 .NET 平台,用来构建高性能的应用系统,其内部集成了异步数据序列的事件驱动编程。

后来,Java 领域也充分借鉴了这一编程模型,诞生了 RxJava 框架,RxJava 可以说是响应式编程得以大规模应用的先驱,推动了一大批针对不同语言的响应式编程框架,这些编程框架同样都以 Rx 作为前缀,例如 RxSwift、RxRuby、RxGo,RxScale、RxKotlin

RxJava 从最初的 1.x 发展到现在的 3.x 版本,各个版本之间变化较大。而从 2.x 版本开始,就对原有的 API 按照响应式流规范进行了重构,并提供了独立的背压功能。

RxJava 应用广泛,例如,在 Netflix 的微服务套件中,熔断器 Hystrix、客户端负载均衡器 Ribbon、API 网关 Zuul 等常用组件中都使用到了 RxJava。除此之外,在以 Android 为代表的 UI 交互开发领域,RxJava 也普遍受到开发人员的欢迎。可以说,其他 Rx 开发库的兴起很大程度上归功于 RxJava 的发展。


Reactor

再来看 Reactor。相较于 RxJava,Reactor 诞生在响应式流规范制定之后,所以从一开始就是严格按照响应式流规范设计并实现了它的 API,这也是 Spring 选择它作为默认响应式编程框架的核心原因

在发展过程中,Reactor 同样经历到从 1.X 到目前 3.X 的演进历程。Reactor 库自早期版本以来已经发展了很多,目前最新的 3.X 版本以 Java 8 作为基线,可以说已经成为业界最先进的响应式库。

RxJava 和 Reactor 二者对比来说,虽然 RxJava 诞生得更早,但 Reactor 应该更有前途。为什么这样说,因为它的开发更活跃,并得到了 Pivotal 公司的大力支持。从 API 角度看,这些库都非常相似,也都提供了一大批非常实用的操作符来简化开发过程。


Project Reactor 框架

Reactor 框架可以单独使用。和集成其他第三方库一样,如果想要在代码中引入 Reactor,要做的事情就是在 Maven 的 pom 文件中添加如下依赖包。

<dependency><groupId>io.projectreactor</groupId><artifactId>reactor-core</artifactId>
</dependency><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-test</artifactId><scope>test</scope>
</dependency>
  • reactor-core 包含了 Reactor 的核心功能,
  • reactor-test 则提供了支持测试的相关工具类

接下来我们将从 Reactor 框架所提供的异步数据序列入手,引出该框架所提供的 Flux 和 Mono 这两个核心编程组件以及相关的操作符。最后,作为响应式流的核心,我对它所具备的背压机制进行讨论。

Reactor 异步数据序列

响应式流规范的基本组件是一个异步的数据序列,在 Reactor 框架中,我们可以把这个异步数据序列表示成如下形式。

Reactor 框架异步序列模型

在这里插入图片描述

上图中的异步序列模型从语义上可以用如下公式表示。

	onNext x 0..N [onError | onComplete]

以上公式中包含了三种消息通知,分别对应在异步数据序列执行过程中的三种不同数据处理场景,其中:

  • onNext 表示正常的包含元素的消息通知;

  • onComplete 表示序列结束的消息通知;

  • onError 表示序列出错的消息通知。

当触发这些消息通知时,异步序列的订阅者中对应的这三个同名方法将被调用。正常情况下,onNext() 和 onComplete() 方法都应该被调用,用来正常消费数据并结束序列。如果没有调用 onComplete() 方法就会生成一个无界数据序列,在业务系统中,这通常是不合理的。而 onError() 方法只有序列出现异常时才会被调用


基于上述异步数据序列,Reactor 框架提供了两个核心组件来发布数据,分别是 Flux 和 Mono 组件。这两个组件可以说是应用程序开发过程中最基本的编程对象。

Flux 和 Mono 组件

Flux

Flux 代表的是一个包含 0 到 n 个元素的异步序列

Reactor 官网给出了它的示意图,如下所示。

在这里插入图片描述

上图中的“operator”代表的是操作符,红色的叉号代表异常,而最后的一个符号则代表序列正常结束。显然,序列的三种消息通知都适用于 Flux。

在详细介绍 Flux的构建和使用方法之前,我们先通过一段简短的代码来演示使用 Flux 的方法,如下所示。

private Flux<Account> getAccounts() {List<Account> accountList = new ArrayList<>();Account account = new Account();account.setId(1L);account.setAccountCode("DemoCode");account.setAccountName("DemoName");accountList.add(account);return Flux.fromIterable(accountList);
}

在以上代码中,我们通过 Flux.fromIterable() 方法构建了 Flux<Account> 对象并进行返回

Flux.fromIterable() 是构建 Flux 的一种常用方法.

我们再来看一个 Web 层组件的代码示例,如下所示。

@GetMapping("/accounts")
public Flux<Account> getAccountList() {Flux<Account> accounts= accountService.getAccounts();return accounts;
}

在这个 Controller 提供的 “/accounts” 的端点中,我们调用了 Service 层方法返回了一个 Account 对象列表,它的数据类型也是 Flux<Account>


Mono

Mono 数据序列中只包含 0 个或 1 个元素

在这里插入图片描述

与 Flux 组件一样,我们同样通过一个服务层的方法来演示 Mono 组件的用法,示例代码如下。

private Mono<Account> getAccountById(Long id) { Account account = new Account();account.setId(id);account.setAccountCode("DemoCode");account.setAccountName("DemoName");accountList.add(account);return Mono.just(account);
}

可以看到,这里首先构建一个 Account 对象,然后通过 Mono.just() 方法返回一个 Mono 对象。

Mono.just() 方法是构建 Mono 的最常见用法之一

同样,Web 层组件获取 Mono<Account> 对象的示例端点如下所示。

@GetMapping("/accounts/{id}")
public Mono<Account> getAccountById(@PathVariable Long id) {Mono<Account> account = accountService.getAccountById(id);return account;
}

显然,某种程度上可以把 Mono 看作是 Flux 的一种特例,而两者之间也可以进行相互的转换和融合。

如果你有两个 Mono 对象,那么把它们合并起来就能获取一个 Flux 对象。除此之外,把一个 Flux 转换成 Mono 对象也有很多办法,例如对一个 Flux 对象中所包含的元素进行计数操作就能得到一个 Mono 对象。而这里合并和计数就是针对数据流的一种操作。Reactor 中提供了一大批非常实用的操作符来简化这些操作的开发过程。


操作符

操作符并不是响应式流规范的一部分,但为了改进响应式代码的可读性并降低开发成本,Reactor 库中的 API 提供了一组丰富的操作符,这些操作符为响应式流规范提供了最大的附加值。操作符的执行效果如下所示。

在这里插入图片描述
在 Reactor 中,可以把操作符分成转换、过滤、组合、条件、数学、日志、调试等几大类,每一类中都提供了一批有用的操作符。尤其是针对转换场景,操作符非常健全. 后面介绍 。


背压处理

背压是所有响应式编程框架所必须要考虑的核心机制

Reactor 框架支持所有常见的背压传播模式,包括以下几种。

  • 纯推模式:这种模式下,订阅者通过 subscription.request(Long.MAX_VALUE) 请求有效无限数量的元素。

  • 纯拉模式:这种模式下,订阅者通过 subscription.request(1) 方法在收到前一个元素后只请求下一个元素。

  • 推-拉混合模式:这种模式下,当订阅者有实时控制需求时,发布者可以适应所提出的数据消费速度。

基于这些背压传播模式,在 Reactor 框架中,针对背压有以下四种处理策略。

  • BUFFER:代表一种缓存策略,缓存消费者暂时还无法处理的数据并放到队列中,这时候使用的队列相当于是一种无界队列。

  • DROP:代表一种丢弃策略,当消费者无法接收新的数据时丢弃这个元素,这时候相当于使用了有界丢弃队列。

  • LATEST:类似于 DROP 策略,但让消费者只得到来自上游组件的最新数据。

  • ERROR:代表一种错误处理策略,当消费者无法及时处理数据时发出一个错误信号。

Reactor 使用了一个枚举类型 OverflowStrategy 来定义这些背压处理策略,并提供了一组对应的 onBackpressureBuffer、onBackpressureDrop、onBackpressureLatest 和 onBackpressureError 操作符来设置背压,分别对应上述四种处理策略。

为了更好地展示操作符的语义和效果,引入弹珠图(Marble Diagram)。弹珠图能将数据流的转换以可视化方式呈现出来,它们对于描述操作符的行为非常有效,因此在 RxJavaReactor 等响应式编程框架中,几乎所有的操作符都包含带有对应的弹珠图的说明。 Reactor 官网给出的 onBackpressureBuffer 操作符的弹珠图如下所示。

onBackpressureBuffer 操作符示意图(来自 Reactor 官网)

在这里插入图片描述

onBackpressureBuffer 操作符有很多种可以选择的配置项,我们可以用来灵活控制它的行为。


小结

针对响应式流规范,业界存储了一批优秀的实现框架,而 Spring 默认集成的 Project Reactor 框架就是这其中的代表。Reactor 框架中最核心的就是代表异步数据序列的 Mono 和 Flux 组件, 我们对这两个组件有了一个初步的认识。同时,我们还介绍了 Reactor 中的操作符组件以及针对不同场景的背压处理机制 。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/14674.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

免费windows pdf编辑工具Epdf

Epdf&#xff08;完全免费&#xff09; 作者&#xff1a;不染心 时间&#xff1a;2025/2/6 Github: https://github.com/dog-tired/Epdf Epdf Epdf 是一款使用 Rust 编写的 PDF 编辑器&#xff0c;目前仍在开发中。它提供了一系列实用的命令行选项&#xff0c;方便用户对 PDF …

计算机组成原理(3)

计算机组成原理&#xff08;3&#xff09; 存储器层次结构存储器概述存储器分类存储器性能指标 半导体随机存储SRAM和DRAM 存储器层次结构 主存-辅存&#xff1a;实现了虚拟存储系统&#xff0c;解决了主存容量不足的问题&#xff1b; Cache-主存&#xff1a;解决了主存于CPU速…

html 列动态布局

样式说明&#xff1a; /* 列动态布局&#xff0c;列之间以空格填充 */ li {display: flex;/* flex-direction: column; */justify-content: space-between; }

25/2/8 <机器人基础> 阻抗控制

1. 什么是阻抗控制&#xff1f; 阻抗控制旨在通过调节机器人与环境的相互作用&#xff0c;控制其动态行为。阻抗可以理解为一个力和位移之间的关系&#xff0c;涉及力、速度和位置的协同控制。 2. 阻抗控制的基本概念 力控制&#xff1a;根据感测的外力调节机械手的动作。位置…

Redis03 - 高可用

Redis高可用 文章目录 Redis高可用一&#xff1a;主从复制 & 读写分离1&#xff1a;主从复制的作用2&#xff1a;主从复制原理2.1&#xff1a;全量复制2.2&#xff1a;增量复制&#xff08;环形缓冲区&#xff09; 3&#xff1a;主从复制实际演示3.1&#xff1a;基本流程准…

蓝桥杯C语言组:图论问题

蓝桥杯C语言组图论问题研究 摘要 图论是计算机科学中的一个重要分支&#xff0c;在蓝桥杯C语言组竞赛中&#xff0c;图论问题频繁出现&#xff0c;对参赛选手的算法设计和编程能力提出了较高要求。本文系统地介绍了图论的基本概念、常见算法及其在蓝桥杯C语言组中的应用&#…

在阿里云ECS上一键部署DeepSeek-R1

DeepSeek-R1 是一款开源模型&#xff0c;也提供了 API(接口)调用方式。据 DeepSeek介绍&#xff0c;DeepSeek-R1 后训练阶段大规模使用了强化学习技术&#xff0c;在只有极少标注数据的情况下提升了模型推理能力&#xff0c;该模型性能对标 OpenAl o1 正式版。DeepSeek-R1 推出…

Ollama + AnythingLLM + Deepseek r1 实现本地知识库

1、Ollama&#xff1a;‌是一个开源的大型语言模型 (LLM)服务工具&#xff0c;旨在简化在本地运行大语言模型的过程&#xff0c;降低使用大语言模型的门槛‌。 2、AnythingLLM&#xff1a;是由Mintplex Labs Inc. 开发的一款全栈应用程序&#xff0c;旨在构建一个高效、可定制、…

(Arxiv-2023)HiPA: 通过高频增强自适应实现一步文本到图像扩散模型

HiPA: 通过高频增强自适应实现一步文本到图像扩散模型 paper是NUS发布在Arxiv 2023的工作 paper title:HiPA: Enabling One-Step Text-to-Image Diffusion Models via High-Frequency-Promoting Adaptation Code&#xff1a;等待开源 Abstract 扩散模型已彻底改变了文本到图像…

Java版本与JDK版本

两者关联 Java版本指的Java语言和平台的版本&#xff0c;例如Java8、Java11、Java17等&#xff0c;每个版本会引入新特性、改进和修复。 JDK(Java Development Kit)版本则是开发工具包&#xff0c;包含编译器、调试器等工具&#xff0c;通常与Java版本对应&#xff0c;例如JDK…

【C语言标准库函数】三角函数

目录 一、头文件 二、函数简介 2.1. 正弦函数&#xff1a;sin(double angle) 2.2. 余弦函数&#xff1a;cos(double angle) 2.3. 正切函数&#xff1a;tan(double angle) 2.4. 反正弦函数&#xff1a;asin(double value) 2.5. 反余弦函数&#xff1a;acos(double value)…

活动预告 |【Part 2】Microsoft 安全在线技术公开课:通过扩展检测和响应抵御威胁

课程介绍 通过 Microsoft Learn 免费参加 Microsoft 安全在线技术公开课&#xff0c;掌握创造新机遇所需的技能&#xff0c;加快对 Microsoft Cloud 技术的了解。参加我们举办的“通过扩展检测和响应抵御威胁”技术公开课活动&#xff0c;了解如何更好地在 Microsoft 365 Defen…

MySQL第五次作业

根据图片内容完成作业 1.建表 &#xff08;1&#xff09;建立两个表:goods(商品表)、orders(订单表) mysql> create table goods( -> gid char(8) primary key, -> name varchar(10), -> price decimal(8,2), -> num int); mysql> create t…

Breakout靶场小试牛刀

1.首先经典两件套 nmap -A 扫描 发现开放很多端口&#xff08;80&#xff0c;10000&#xff0c;20000为重点关注&#xff09; 问题不大&#xff0c;先dirsearch扫一下目录再说 结果能看的manual里啥也没有&#xff0c;之后再查看80端口界面源代码 发现有一串字符 但是问了ai…

Vue el-tree 加载过滤出的父节点以及其包含的子节点

由于el-tree提供的过滤函数&#xff0c;过滤出来的目录节点不包含子节点&#xff0c;因此需要改造过滤函数&#xff0c;使其过滤出的目录节点包含子节点。 <template><div><el-input placeholder"请输入内容" v-model"filterText" clearab…

认识O(NlogN)的排序

归并排序 归并排序&#xff08;任何一个递归&#xff09;如果不懂可以画一个树状结构去帮助自己去理解。 核心排序方法为Merger public class 归并排序 {public static void main(String[] args) {int[] arr1 {3, 1, 2, 2, 5, 6};int[] arr2 Arrays.copyOf(arr1, arr1.len…

如何使用Gemini模型,国内如何订阅购买Gemini Pro的教程,Gemini Pro 免费试用操作步骤, 谷歌 aistudio 使用入口

最近的榜首又被Gemini给霸占了&#xff0c;很多童鞋想要体验一翻 Gemini免费库模型更新了 Gemini2.0向所有人开放了&#xff01;使用了真香 目前呢2.0flash和Gemini-2.0-Flash-Thinking-Exp、Gemini-2.0-Flash-Thinking-Exp-with-apps已经免费给所有注册用户开放了&#xff0c…

【数据结构】(7) 栈和队列

一、栈 Stack 1、什么是栈 栈是一种特殊的线性表&#xff0c;它只能在固定的一端&#xff08;栈顶&#xff09;进行出栈、压栈操作&#xff0c;具有后进先出的特点。 2、栈概念的例题 答案为 C&#xff0c;以C为例进行讲解&#xff1a; 第一个出栈的是3&#xff0c;那么 1、…

安宝特方案 | AR助力制造业安全巡检智能化革命!

引言&#xff1a; 在制造业中&#xff0c;传统巡检常面临流程繁琐、质量波动、数据难以追溯等问题。安宝特AR工作流程标准化解决方案&#xff0c;通过增强现实AR技术&#xff0c;重塑制造业安全巡检模式&#xff0c;以标准化作业流程为核心&#xff0c;全面提升效率、质量与…

语言月赛 202308【小粉兔做麻辣兔头】题解(AC)

》》》点我查看「视频」详解》》》 [语言月赛 202308] 小粉兔做麻辣兔头 题目描述 粉兔喜欢吃麻辣兔头&#xff0c;麻辣兔头的辣度分为若干级&#xff0c;用数字表示&#xff0c;数字越大&#xff0c;兔头越辣。为了庆祝粉兔专题赛 #1 的顺利举行&#xff0c;粉兔要做一些麻…