RxJava(一:functional reactive programming)

在RxJav的开始,介绍下本博客所讲所涉及的范围:
1.函数式响应性编程概念:将会介绍函数式编程,然后继续讨论响应式声明和响应式编程概念
2.Observable创建,组合以及过滤:介绍RxJava库如何创建一个被称为“Observable”的对象。Observable的内容构成了RxJava响应式扩展库的工作原理。然后,我们将讨论RxJava如何将操作组合在一起,以形成复杂的业务逻辑,这些业务逻辑由单个简单的部分组成。接下来接下来,我们将研究如何创建过滤器,以修改可观察事件流的内容。
3.探讨允许您转换Observable流的事件的一些操作。我我们还将检查条件操作。条件操作允许您通过使用另一个流作为逻辑网关的类型来控制流的输出。
4.我们将开始将所有东西都放在一起,包括可连接的Observables、资源管理,以及发布/订阅subjects 。这些组件提供了RxJava以与系统资源绑定的能力,例如文件或数据库连接,而subjects允许您创建应用程序逻辑,通过使用发布/订阅事件模型完全解耦。
5.最后,实战

1.函数响应式编程

1.1 概念简介

这里写图片描述

首先,我将讨论函数式编程。函数式编程就是要使您的代码可预见和线程安全。它还奠定了使响应式编程成为可能的基础。函数式编程是一个巨大的主题,因此我们将介绍它的三个主要思想。我们将讨论纯函数。纯函数是所有函数的起点。接下来,我们将研究使函数成为语言一级公民的功能意味着什么。最后,我们把这些概念放在一起描述高阶函数:返回其他函数的函数。接下来,我们将讨论响应式编程概念。我们将讨论响应式的宣言,这是一个在线文档,它为响应式编程提供了一个很高的门槛。这意味着什么呢??在响应式的宣言中它意味着使我们的应用程序是事件驱动的,这样它们的结构就可以很好地处理并发性,而且是一个很好的结构,可以相互解耦不同的模块。我们将研究如何使用这些相同的概念使我们的应用程序可伸缩,使您的应用程序能够适应负载和故障条件的变化。最后,让他们对用户响应。

1.2 函数式编程—纯函数

我们要看的第一个函数式编程概念是纯函数的概念。所以我们将从一个代码演示开始,看看我们是否能理解什么是纯的,没有副作用。

这里写图片描述

①f1只接受一个参数,它将x这个参数乘以2,然后返回。不管这个类有多少线程,它的行为方式也是一样的。它不依赖于类中的任何状态。它不以任何方式使用state变量。而且,因为在多个线程中没有任何有竞争的状态存在,所以不需要任何类型的同步代码。因此,这个f1函数被认为是纯函数,因为它没有基于对象的状态、类的状态、任何I/O设备的状态,或者基于时间的任何副作用。这是一个纯函数。
②接下来,我们将看f2函数,它取一个整数。然后它会做一些疯狂的事情。它取state变量,将它加1;然后与3取模,最终将得到的值存储到state变量中,然后将入参乘以2后加上state变量的值,一起作为返回值。所以f2函数基于state变量的副作用行为,而返回不同的结果。如果你有一堆线程穿过f2函数,结果将是不可预测的。
最后,一起来看main方法。我们先看③,在这个函数中,我没有把线程放在这里只是为了简单,只要我在调用f1(5)的时候返回值不是10,那么我就会抛出异常,但是很显然,这是永远不会发生的。
然后我们再看④,这里调用了100次f2(5),我们将返回值做了打印。当然不需要截图你也知道最终的记过肯定是基本不相同的一堆数字。


SO:
对于任何纯函数,你传入相同的值,不管你调用多少次,或者是多线程高并发,返回值都是一样的。这是一个纯函数的定义,因为它没有基于类、I/O设备或任何其他与时间相关的副作用。在我们的代码示例中,我们看到了f1函数是一个纯函数的例子。不管你输入什么,你总会得到一个可预测的值,不管有多少线程,不管条件如何,你总是会得到相同的结果。我们看到f2函数是不确定的因为它的结果很大程度上取决于这个方法被调用的顺序。这是一个不纯函数的例子。

1.3 函数式编程——作为一等公民的功能

不知道在看的各位,是否已经熟悉掌握Java8的Lambda表达式以及函数接口,这里假定您已经会了。

这里写图片描述

这里写图片描述

所以我们看到,函数式可以作为一等公民的,因为它已经被我们存储进变量了。
接下来,我们将研究它们如何作为参数传递。

这里写图片描述

这是一个函数作为一类公民,具有可以作为参数传递能力的例子。
让我们回顾。我们看了一些代码,它向我们展示了Java 8是如何将函数作为一流公民对待的。通过这个代码示例,我们看到了利用该功能的所有不同方法。在我们的代码示例中,我们研究了变量如何在Java 8中包含函数,以及这些函数如何以变量和行的形式作为参数传递。

1.4 函数式编程—高级函数

直接上代码:

这里写图片描述

首选看静态方法createConbineAndTransform,入参与我们上面1.3中使用的基本一致,只不过1.3我们返回的是结果,而该方法返回的是一个函数对象,也可以说是lambda表达式。
那么什么是高级函数:接收一个函数,并返回一个复合函数。
在我们的例子汇总,方法createConbineAndTransform接收了一个Function的函数入参,返回了一个Supplier的结果函数,该函数的执行结果是一个String字符串,也就是我们所期望得到的组合后的字符串。
我们来看main方法,我们从createConbineAndTransform方法得到了一个Supplier函数对象,然后我们通过调用它的get()方法,取得了我们的结果。那么函数是在什么时候执行的呢??答案其实在调用get方法时候,执行其逻辑的,好奇的小伙伴可以去String的toUpperCase里打个断点,即知道执行了。
函数的执行时间对于RxJava是一个很重要的概念

1.5 响应式宣言,

响应式宣言是一个在线文档,为软件开发行业中的应用提供了一个高标准。让我们来讨论一下响应式编程的四个主要概念,如在响应式宣言中所阐述的:
1.首先是事件驱动的。事件驱动的应用程序以一种有助于促进并发性的方式组织起来。这种类型的应用程序结构也提供了解耦,使应用程序更易于维护和可扩展。
2.接下来,是可伸缩性。在响应式声明中,我们希望我们的应用程序能够动态地伸缩。如果系统出现意外负载,我们应该能够简单地启动应用程序的更多实例,以实现无缝扩展。当我们谈到利用云基础设施时,这一点尤为重要。这种情况又回归到了事件驱动。事件驱动的应用程序天生具有支持并发性的结构。
3.然后就是弹性。在高容量下的应用程序必须在没有附带系统的情况下进行通信,通常会出现短期的中断或故障。在现代的面向服务的系统中,如果我们依赖的服务下降,那么我们的应用程序通常也会被降低。特别是当依赖系统的响应时间上升时,在源服务中造成线程或其他资源阻塞。在一个响应式的世界中,我们希望我们的应用程序能够优雅地处理这些情况
4.最后,响应式应用程序是响应性的。在面对高请求量时,我们必须保持对用户的良好服务水平。响应式应用程序可以通过标准的编码,确保它们能够响应并最大限度地利用可用资源。

1.6 响应式宣言-事件驱动

我们首先讲事件驱动概念。RxJava是以观察者模式,实现的实现驱动。

这里写图片描述

让我们回顾一下观察者模式对我们的意义以及它是如何工作的。在观察者模式中,你有一个observable(可观察)的对象。您可以有一个或多个订阅到observable的observers(观察者),并且一旦完成了对observable的更改,就会作为通知发送给observers(观察者)。这些通知可以是同步的,也可以是并发的;这取决于执行情况。

这里写图片描述

我们来讨论一下RxJava的观察者模式。在它的使用中,仍然有一个可observable,而且仍然有observers(观察者),但是我们要做一个微小的改变。我们将会有Observable、可观察到的特定类型的事件以及观察指定类型的事件的Observer(观察者)。因此,当事件被发送到这个Observable对象时,他们有特定的类型。然后这个通知会以异步的形式发送给每个观察者。这给了我们一个与从observable到observer的事件相关的强类型系统。
您可能会注意到,本例中的observer(观察者)是完全被动的。当他们坐在那里等待一个事件时,他们没有占用任何资源。这对于事件驱动的应用程序的内存效率和一般资源效率非常重要。因此,让我们来看看一个特定的事件驱动的例子,看看我们如何使用RxJava库来实现一些有趣的事。

这里写图片描述

对于①,我们有一个Observable,它返回用户这种类型的event(事件),换句话说,虽然实际上它确实是一个user列表,但是你要将user想象为一个event(事件)对象。当你在RxJava中考虑观察者模式时候,你可以把任何东西都看做是event(事件)的列表,尽管RxJava为我们提供了一些工具可以转换这些列表。
我们将会有一个观察user类型事件的观察者,即图③,这个观察者会过滤掉那些没有被标记为管理员的user(这是③的业务逻辑)。RxJava要为我们做的事情之一就是我们要指定一个Scheduler(调度器)用于执行这个操作。我们会说这是可以并行处理的。因此,RxJava有几种不同的调度程序可供选择。我们告诉他我们想要什么样的调度程序,而他只是为我们处理线程。现在我们已经过滤了不是管理员的user了,当它发生时,这一小段代码本身将返回一个泛型是user的Observable对象,我们可以有另一个Observer(观察者)通过安全等级来分组我们的user,见图④。在这种情况下,用户的分组是没法并行操作的,所以我们告诉他这将是一个串行操作。当它发生时,这一段小的代码段也将返回一个泛型是user的Observable对象,这些用户根据它们的安全等级被排好序。
接下来,我们将会有一个Observer(观察者),它接受ORM形式的user,或许它将其转换为一个JSON格式的user Bean,或者把它映射成我们可以向外部世界提供的东西(比如XML等)。这个过程也可以使用scheduled(调度器) 。因此,我们将告诉RxJava使用特定的调度器,它将为我们处理线程。

现在总体看一下这个图,考虑一下RxJava对我们带啦什么改变?它贡献了观察者模式,使我们字需要编写了小的可管理的代码,而且这些代码的副作用非常小。我们在上面解释过纯函数的概念,这就是它的切入点。RxJava还提供了它的调度器,为我们提供线程管理的能力。

1.7 响应式宣言-可扩展

在讨论可拓展性之前,我们需要回顾一下上面讲到的事件驱动中,我们特别的指出了在Observer(观察者)对象中使用的管理线程的调度器。在讨论可伸缩性时,这也是一个重要的细节,因为是RxJava为你处理并发性。没有必要编写大量复杂的线程代码或java的Future方面的代码。这些细节都由RxJava处理。因此,让我们讨论一下并发执行如何以具体的方式帮助我们的应用程序的性能。
现在假设我们有一个user Facade service(用户门户服务),它又能会去调用Security Service(安全服务)或者是Payment History Service(支付历史服务),再然后是我们的Payment Service(支付服务)。

这里写图片描述

假设现在有一个请求来调用我们的user Facade service(用户门户服务),而它会去调用Security Service(安全服务),让我们把调用安全服务的事件记为变量X。接下来,它调用Payment History Service(支付历史服务),我们将把变量Y分配给调用它的时间。然后它调用我们的Payment Service(支付服务),调用花费的时间是一个变量Z.我添加了一个A来表示调其他的花费时间。因此,如果您以串行的方式调用它们,而不是并行调用的话,这个示例的总执行时间为A + X + Y + Z。

这里写图片描述

接下来,让我们以我们的示例为例,做一些修改。我改变了线和箭头。这些虚线,表示这是异步并发调用。现在X,Y,Z同时发生。现在让我们看看这个例子的总执行时间=Max(X,Y,Z) + A。因此,正如您所看到的,通过并行执行这些操作来执行相同的服务集是一种更快的方式。

1.8 响应式宣言——弹性

弹性的应用程序体现了两个重要的属性。第一个是优雅的错误处理。我们的代码通常只关注应用程序执行正确的情况,将错误处理作为检查异常处理的意外副作用。在有弹性的应用程序中,我们希望看到可能发生的错误或异常的类型,并确保以一种方式处理这些错误,如果可能的话,仍然能为我们的用户提供价值。例如,假设我们正在尝试使用一个已经关闭了或正在经历太多延迟的User Service(用户服务)创建一个新用户。并不是向我们的用户显示一个500的错误页面,或者设置一个错误页面,这种范式除了高速用户出现了一些可怕的情况之外,没有什么其他用处。相反,我们将创建新用户的请求排队等候。现在我们可以向用户显示一个屏幕,向他们道歉并告诉他们User Service(用户服务)目前是不可用的,但是我们已经排队了他的请求,当我们成功创建了他们的帐户后,他们将收到一个电子邮件验证。在这种情况下,即使我们失败了,但是我们仍然会满足用户的请求,而且没有信息丢失。弹性意味着我们能够优雅地处理错误,而不是简单地返回一个错误页面。
我想讨论的弹性应用程序的第二个特性是管理失败。在我们之前的User Service(用户服务)示例中,服务调用虽然失败了,我们的应用程序以一种仍然提供值的方式响应失败。现在让我们讨论一个场景,在这个场景中,User Service(用户服务)在三个不同的机器上运行。我们希望我们的软件能够检测到其中一个实例已经停止响应并适当地采取行动。当服务集群的一部分开始出现错误行为时,通常发生的情况是,依赖于该服务的其他功能也开始出现故障。通常这些失败或线程锁定,会通过系统进行备份,最终导致整个系统宕掉。

当创建有弹性的应用程序时,我们希望检测这个状态,并使用失败或潜在的服务来停止它,这样它就不会影响系统中的其他元素。这就是在可能失败的系统组件周围创建隔板的想法。关于管理失败,我想说的下一点是位置透明性。因为一个响应式的应用程序使用事件驱动结构,这个结构使得非常自然的创建那些不关心在什么地方执行的组件。创建服务的新实例对于补偿失败或需要动态地扩展应用程序时,变得更加容易实现。这个属性有助于我们系统的整体弹性。

响应式宣言——响应性

最后,让我们讨论响应式应用程序的响应性。
我想讲两个属性:
    ①首先,在一个响应式的应用程序中,我们将在编程中做一些奇怪而闻所未闻的事情。我们要说的是,如果某些东西响应缓慢,而且不仅仅是慢,还是失败的。以这种新的方式来思考我们的应用程序,那些耗费太长的时间的代码导致启动了应用的弹性机制,表现得好像失败了一样。因此功能应该被降级,而不是简单地允许缓慢执行。以这种方式编写应用程序将对我们的代码产生一些重要的影响。我们必须建立起机制,当我们的代码的重要部分运行缓慢时,可以检测到。接下来,我们将不得不定义一个超时时间,标识在认为失败之前最大允许等待时间。当然这个事件并不是凭空的指定,需要保证你的超时时间不会影响到性能。
    ②响应性应用程序的下一个属性是可观察数据模型的概念。其中一个流行的实现是MVVM或模型视图ViewModel模式。当模型中的数据更新时,视图模型对象会自动更新,以使UI组件刷新信息。当应用程序以这种方式编写时,不会有一些循环代码驱动对UI的更新。相反,当一个有趣的事件发生时,模型就会被更新,而UI的其余部分也会自动处理。换句话说,由用户与应用程序交互的事件流将异步地改变模型。这样做不会阻碍UI。相反,异步代码被执行,当代码完成时,应用程序使用的模型将被直接更新。使用MVVM模式,一旦发生这种情况,UI就会自动处理。有了这种应用程序结构,创建响应式的用户界面就更容易了。

猜你喜欢

转载自blog.csdn.net/qq_31179577/article/details/78745248