Flux、Mono、Reactor 实战(史上最全)

响应式编程(二)Mono<T>、Flux<T> 方法大全 阅读详情

文章很长,建议收藏起来慢慢读! 疯狂创客圈 总目录 为您奉上珍贵的学习资源 :


前言

响应式编程用的是越来越多,尤其是在移动端 安卓的应用上边。

在Java后台服务开发中, 响应式编程用的不是太广泛,主要原因是, 响应式编程需要一个完整的生态, 包括数据库、缓存、中间件,都需要配套的响应式组件。 但是这点,其实很多并没有。

但是,随着 SpringCloud Gateway 的火爆, 响应式编程又变成了 不可回避, 不得不去学习的技术。

如果要做 SpringCloud Gateway 的开发, 就必须掌握一些响应式编程的知识。 由于最近在做 spring cloud gateway相关的开发工作, 所以:

把响应式编程Flux 和 Mono 的知识梳理一下,形成了此文。

并且,此文会不断完善。

姊妹篇:关于 SpringCloud Gateway 简介

SpringCloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 2.0之前的非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

Spring Cloud Gateway 的目标,不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

有关 Spring Cloud Gateway 响应式编程的实战, 具体请参考本文姊妹篇:

《SpringCloud gateway (史上最全))》

特别说明:

Spring Cloud Gateway 底层使用了高性能的通信框架Netty。

Netty 是高性能中间件的通讯底座, rocketmq 、seata、nacos 、sentinel 、redission 、dubbo 等太多、太多的的大名鼎鼎的中间件,无一例外都是基于netty。

可以毫不夸张的说: netty 是进入大厂、走向高端 的必备技能。

要想深入了解springcloud gateway ,最好是掌握netty 编程。

有关 netty学习 具体请参见机工社出版 、尼恩的畅销书: 《Java高并发核心编程卷 1》

响应式编程概述

背景知识

为了应对高并发服务器端开发场景,在2009 年,微软提出了一个更优雅地实现异步编程的方式——Reactive Programming,我们称之为响应式编程。随后,Netflix 和LightBend 公司提供了RxJava 和Akka Stream 等技术,使得Java 平台也有了能够实现响应式编程的框架。

在2017 年9 月28 日,Spring 5 正式发布。Spring 5 发布最大的意义在于,它将响应式编程技术的普及向前推进了一大步。而同时,作为在背后支持Spring 5 响应式编程的框架Spring Reactor,也进入了里程碑式的3.1.0 版本。

什么是响应式编程

响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。

响应式编程基于reactor(Reactor 是一个运行在 Java8 之上的响应式框架)的思想,当你做一个带有一定延迟的才能够返回的io操作时,不会阻塞,而是立刻返回一个流,并且订阅这个流,当这个流上产生了返回数据,可以立刻得到通知并调用回调函数处理数据。

电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。

响应式传播核心特点之一:变化传播:一个单元格变化之后,会像多米诺骨牌一样,导致直接和间接引用它的其他单元格均发生相应变化。

基于Java8实现观察者模式

Observable类:此类表示可观察对象,或模型视图范例中的“数据”。

它可以被子类实现以表示应用程序想要观察的对象。

//想要观察的对象 ObserverDemo
public class ObserverDemo extends Observable {
    public static void main(String[] args) {
        ObserverDemo observerDemo = new ObserverDemo();
        //添加观察者
        observerDemo.addObserver((o,arg)->{
            System.out.println("数据发生变化A");
        });
        observerDemo.addObserver((o,arg)->{
            System.out.println("数据发生变化B");
        });
        observerDemo.setChanged();//将此Observable对象标记为已更改
        observerDemo.notifyObservers();//如果该对象发生了变化,则通知其所有观察者
    }
}

启动程序测试:

在这里插入图片描述

创建一个Observable

rxjava中,可以使用Observable.create() 该方法接收一个Obsubscribe对象

Observable<Integer> observable = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {

            }
        });

来个例子:

        Observable<Integer> observable=Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {
                for(int i=0;i<5;i++){
                    subscriber.onNext(i);
                }
                subscriber.onCompleted();
            }
        });
        //Observable.subscribe(Observer),Observer订阅了Observable
        Subscription subscribe = observable.subscribe(new Observer<Integer>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "完成");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "异常");
            }

            @Override
            public void onNext(Integer integer) {
                Log.e(TAG, "接收Obsverable中发射的值:" + integer);
            }
        });

输出:

 接收Obsverable中发射的值:0
接收Obsverable中发射的值:1
接收Obsverable中发射的值:2
接收Obsverable中发射的值:3
接收Obsverable中发射的值:4

从上面的例子可以看出,在Observer订阅了Observable后,

Observer作为OnSubscribe中call方法的参数传入,从而调用了Observer的相关方法

基于 Reactor 实现

Reactor 是一个运行在 Java8 之上满足 Reactice 规范的响应式框架,它提供了一组响应式风格的 API。

Reactor 有两个核心类: Flux<T> 和 Mono<T>,这两个类都实现 Publisher 接口。

  • Flux 类似 RxJava 的 Observable,它可以触发零到多个事件,并根据实际情况结束处理或触发错误。
  • Mono 最多只触发一个事件,所以可以把 Mono 用于在异步任务完成时发出通知。

preview

Flux 和 Mono 都是数据流的发布者,使用 Flux 和 Mono 都可以发出三种数据信号:元素值,错误信号,完成信号;错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者。

三种信号的特点:

  • 错误信号和完成信号都是终止信号,不能共存
  • 如果没有发送任何元素值,而是直接发送错误或者完成信号,表示是空数据流
  • 如果没有错误信号,也没有完成信号,表示是无限数据流

引入依赖

        <dependency>
            <groupId>org.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
            <version>1.1.6.RELEASE</version>
        </dependency>

just 和 subscribe方法

just():创建Flux序列,并声明指定数据流

subscribe():订阅Flux序列,只有进行订阅后才回触发数据流,不订阅就什么都不会发生

public class TestReactor {
    public static void main(String[] args) {
        //just():创建Flux序列,并声明数据流,
        Flux<Integer> integerFlux = Flux.just(1, 2, 3, 4);//整形
        //subscribe():订阅Flux序列,只有进行订阅后才回触发数据流,不订阅就什么都不会发生
        integerFlux.subscribe(System.out::println);
        
        Flux<String> stringFlux = Flux.just("hello", "world");//字符串
        stringFlux.subscribe(System.out::println);
        
        //fromArray(),fromIterable()和fromStream():可以从一个数组、Iterable 对象或Stream 对象中创建Flux序列
        Integer[] array = {1,2,3,4};
        Flux.fromArray(array).subscribe(System.out::println);
        
        List<Integer> integers = Arrays.asList(array);
        Flux.fromIterable(integers).subscribe(System.out::println);
        
        Stream<Integer> stream = integers.stream();
        Flux.fromStream(stream).subscribe(System.out::println);
    }
}

启动测试:

在这里插入图片描述

响应流的特点

要搞清楚这两个概念,必须说一下响应流规范。它是响应式编程的基石。他具有以下特点:

  • 响应流必须是无阻塞的。

  • 响应流必须是一个数据流。

  • 它必须可以异步执行。

  • 并且它也应该能够处理背压。

  • 即时响应性: 只要有可能, 系统就会及时地做出响应。 即时响应是可用性和实用性的基石, 而更加重要的是,即时响应意味着可以快速地检测到问题并且有效地对其进行处理。 即时响应的系统专注于提供快速而一致的响应时间, 确立可靠的反馈上限, 以提供一致的服务质量。 这种一致的行为转而将简化错误处理、 建立最终用户的信任并促使用户与系统作进一步的互动。

  • **回弹性:**系统在出现失败时依然保持即时响应性。 这不仅适用于高可用的、 任务关键型系统——任何不具备回弹性的系统都将会在发生失败之后丢失即时响应性。 回弹性是通过复制、 遏制、 隔离以及委托来实现的。 失败的扩散被遏制在了每个组件内部, 与其他组件相互隔离, 从而确保系统某部分的失败不会危及整个系统,并能独立恢复。 每个组件的恢复都被委托给了另一个(外部的)组件, 此外,在必要时可以通过复制来保证高可用性。 (因此)组件的客户端不再承担组件失败的处理。

  • 弹性: 系统在不断变化的工作负载之下依然保持即时响应性。 反应式系统可以对输入(负载)的速率变化做出反应,比如通过增加或者减少被分配用于服务这些输入(负载)的资源。 这意味着设计上并没有争用点和中央瓶颈, 得以进行组件的分片或者复制, 并在它们之间分布输入(负载)。 通过提供相关的实时性能指标, 反应式系统能支持预测式以及反应式的伸缩算法。 这些系统可以在常规的硬件以及软件平台上实现成本高效的弹性。

  • **消息驱动:**反应式系统依赖异步的消息传递,从而确保了松耦合、隔离、位置透明的组件之间有着明确边界。 这一边界还提供了将失败作为消息委托出去的手段。 使用显式的消息传递,可以通过在系统中塑造并监视消息流队列, 并在必要时应用回压, 从而实现负载管理、 弹性以及流量控制。 使用位置透明的消息传递作为通信的手段, 使得跨集群或者在单个主机中使用相同的结构成分和语义来管理失败成为了可能。 非阻塞的通信使得接收者可以只在活动时才消耗资源, 从而减少系统开销。

Publisher/Flux和Mono

由于响应流的特点,我们不能再返回一个简单的POJO对象来表示结果了。必须返回一个类似Java中的Future的概念,在有结果可用时通知消费者进行消费响应。

Reactive Stream规范中这种被定义为Publisher

Publisher是一个可以提供0-N个序列元素的提供者,并根据其订阅者Subscriber<? super T>的需求推送元素。

一个Publisher可以支持多个订阅者,并可以根据订阅者的逻辑进行推送序列元素。

下面这个Excel计算就能说明一些Publisher的特点。

img

A1-A9就可以看做Publisher及其提供的元素序列。

A10-A13分别是求和函数SUM(A1:A9)、平均函数AVERAGE(A1:A9)、最大值函数MAX(A1:A9)、最小值函数MIN(A1:A9),

A10-A13可以看作订阅者Subscriber。

假如说我们没有A10-A13,那么A1-A9就没有实际意义,它们并不产生计算。

这也是响应式的一个重要特点:当没有订阅时发布者什么也不做。而Flux和Mono都是Publisher在Reactor 3实现。

Publisher提供了subscribe方法,允许消费者在有结果可用时进行消费。

如果没有消费者Publisher不会做任何事情,他根据消费情况进行响应。

Publisher可能返回零或者多个,甚至可能是无限的,为了更加清晰表示期待的结果就引入了两个实现模型Mono和Flux。

Flux

Flux 是一个发出(emit)0-N个元素组成的异步序列的Publisher,可以被onComplete信号或者onError信号所终止。

在响应流规范中存在三种给下游消费者调用的方法 onNext, onComplete, 和onError。下面这张图表示了Flux的抽象模型:

img

以上的的讲解对于初次接触反应式编程的依然是难以理解的,所以这里有一个循序渐进的理解过程。

有些类比并不是很妥当,但是对于你循序渐进的理解这些新概念还是有帮助的。

传统数据处理

我们在平常是这么写的:

public List<ClientUser> allUsers() {
    return Arrays.asList(new ClientUser("felord.cn", "reactive"),
            new ClientUser("Felordcn", "Reactor"));
}

我们通过迭代返回值List来get这些元素进行再处理(消费),不管有没有消费者, 菜品都会生产出来。

流式数据处理

在Java 8中我们可以改写为流的表示:

public Stream<ClientUser> allUsers() {
    ret
Reactor (1)Mono和Flux进行响应式编程介绍 Reactor Mono和Flux进行反应式编程 官网:https://projectreactor.io/ 教程:https://projectreactor.io/docs/core/release/reference/#about-doc 1、Reactor反应式编程介绍 ​ 反应式编程来源于数据流和变化的传播,意味着由底层的执行模型负责通过数据流来自动传播变化。比如求值一个简单的表达式 c=a+b,当 a 或者 b 的值发生变化时,传统的编程范式需要对 a+b 进行重新计算来得到 c 的值。如果使 阅读详情

相关推荐

Reactor系列(二)Flux Mono创建

Flux Mono创建 Reactor系列(二)Flux Mono创建 FluxMonoTestCase.java package com.example.reactor; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux;...

wenhaipan的博客 1206

响应式编程框架Reactor之 Flux 和 Mono 的介绍和区别

基本概念Mono是Reactor中的一个类,它表示一个异步的单个值或零个值的结果。Mono可以看作是一个特殊的Publisher,用于产生数据流,但这个数据流最多只包含一个元素,或者在没有任何元素时直接发出完成信号或错误信号。作用Mono主要用于处理那些预期会返回一个单一结果或不需要返回任何结果的异步操作,如数据库查询(假设查询结果是唯一的)、网络请求等。它提供了丰富的操作符来支持数据的转换、过滤、组合等操作,以及错误处理和资源管理等。创建方式可以通过Mono的静态方法创建,如等。

oscar999的专栏 1944

掌握Reactor:Mono和Flux的实战教程

响应式编程是一种基于数据流和变化传播的编程范式,它使应用程序可以更自然地表达动态数据处理的异步和基于事件的程序。Reactor是Spring WebFlux的底层响应式库,它使用Project Reactor作为响应式编程模型的基础。本章将带您快速进入Reactor的世界,并概览其背后的核心概念。响应式编程是一种关注于数据流和变化传播的编程模式。它的核心思想是使用异步数据流来构建非阻塞的异步应用程序。

weixin_42598278的博客 1399

Reactor教程Mono和Flux例子

Reactor教程Mono和Flux例子,同时可以查看我的博客,有介绍如何使用Reactor的详细教程

Cadence 17.2配置CIS数据库报错?手把手解决ODBC驱动位数不匹配问题

本文详细解析了Cadence 17.2配置CIS数据库时常见的ODBC驱动位数不匹配问题,提供了从系统环境检查到分步解决方案的完整指南。重点解决32位应用程序与64位ODBC驱动之间的架构冲突,包含驱动安装、DSN配置及高级排查技巧,帮助电子工程师快速恢复设计环境。

play7的博客 970

STC89C52RC单片机原理图详解

左侧A0和右侧B0为一 一对应的关系,左上角DIR为控制数据方向端口,如果DIR接高电平是将左侧数据A0~A8送到右侧B0~B8,如果DIR接低电平,是将右侧数据B0~B8送到左侧A0~A8,由于在电路板上LE始终与VCC连接,因此这里。74HC595是串行输入,并行输出的移位寄存器,可用3根线输入串行数据,8根线输出并行数据,多片级联后,可输出16位、24位、32位等,常用于I/O口扩展。由于数码管为共阴极,给数码管下面接口输入阳码时,LED才亮,但是直接将P0~P7的高电平输入到数码管时,

m0_50562428的博客 6万+

NVIDIA Orin AGX开发环境搭建避坑指南:从Ubuntu 22.04到ROS2完整配置流程

本文详细介绍了NVIDIA Orin AGX开发环境搭建的全流程,从Ubuntu 22.04系统安装到ROS2深度优化,涵盖驱动部署、CUDA环境配置、散热与功耗管理等关键步骤。特别针对Orin AGX的特性提供了实用避坑指南和性能优化技巧,帮助开发者高效完成开发环境配置。

weixin_28340315的博客 451

基于R语言的PLS算法实现解读

我们使用"pls"包来执行PLS回归,并提供了相应的源代码。在本文中,我们将详细解读基于R语言的PLS算法的实现过程,并提供相应的源代码。PLS算法的实现可以借助R语言中的"pls"包。该包提供了丰富的函数和工具,用于执行PLS回归、PLS-DA(PLS-Discriminant Analysis)和其他相关任务。除了执行PLS回归,"pls"包还提供了其他功能,例如PLS-DA(用于分类问题)和PLS变量选择等。上述代码将基于输入的X值,使用训练好的PLS模型进行预测,并返回预测结果。

TechWhizKid的博客 1046

鲁棒优化 (Robust Optimization) 算法详解及案例分析

鲁棒优化是一种用于处理不确定性优化问题的方法。其目标是在不确定性参数的可能取值范围内,找到一个对不确定性具有鲁棒性的解。

闲人编程的博客 4329

[QMT量化交易小白入门]-七、可转债双低策略Python代码详解与实战

本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步,自己淋过雨了,希望大家都有一把伞。

木头大左的博客 3861

11、气动外形优化中的连续伴随方法

本文探讨了连续伴随方法在气动外形优化中的理论背景、实现和验证过程。通过使用DLR的FLOWer求解器,将伴随方法应用于Euler和Navier-Stokes方程,以高效计算成本函数梯度,从而显著减少优化过程中的计算成本。文章还介绍了该方法在RAE2822翼型和ONERA M6机翼等案例中的应用,并展示了其准确性和效率。未来展望包括扩展到复杂流动模拟和多学科优化。

desk3的博客 167

基于opencv的鱼群检测和数量统计识别鱼群密度带界面

摘要:本项目利用OpenCV图像处理技术实现了视频鱼类自动检测计数系统。通过背景减除、形态学处理和轮廓检测等方法,在视频帧中标记鱼类并统计数量。系统包含视频读取、前景提取、轮廓分析、中心点跟踪等核心功能,可实时显示计数结果。适用于水产养殖、生态监测等领域,具有实用价值。未来可通过参数优化、引入深度学习和多目标跟踪技术进一步提升准确性。(147字)

1720

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: 110道 MySQL面试题及答案 (持续更新)
下一篇: 2019中原银行java实习面试
AIGC镜像空间
博客等级 码龄5年 4万+粉丝 689原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值