Soul源码解析(5)-响应式编程
一、目标
1、了解Soul网关采用的响应式编程
二、内容
2.1 背景
响应式编程(Reactive Programming)是近几年来非常流行的一个解决方案,比如:
- Java 8 => 引入Stream流,Observable 和 Observer 模式
- Spring 5 => 引入WebFlux,底层全面采用了响应式模型
- RxJava => 随着程序逻辑变得越来越复杂,它依然能够保持简洁
2.2 什么是响应式编程?
响应式编程是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者为新的消费者与另外一条流合并为一条新的流;
响应式编程的一个关键概念是事件。事件可以被等待,可以触发过程,也可以触发其它事件;
RP推崇面向流的编程的思想,无论是事件还是数据,全部都将以流的方式呈现,这些流时而并行,时而交叉,编程就是观察和调控这些流的一个过程;
RP从现实世界进行抽象和采样,将程序分为了以下三种组成
-
Observable:可被观察的事物,也就是事件和数据流
-
Observer:观察流的事物
-
Operator:操作符,对流进行连接和过滤等等操作的事物
//把几个字符串先取长度,然后再逐个输出 Observable<String> myStrings = Observable.just("Alpha", "Beta", "Gamma", "Delta", "Epsilon"); myStrings.map(s -> s.length()) .subscribe(s -> System.out.println(s));
在上面的例子中,
myStrings
就是Observable,map(s -> s.length())
就是Operator,subscribe(s -> System.out.println(s))
就是Observer;Observable
Observable简单来说,就是流,在RxJava中只有三个最核心的API:
-
onNext()
:传递一个对象 -
onComplete()
:传递完成的“信号” -
onError()
:传递一个错误
基本上所有的流都是这三种方法的一个包装
- 创建
-
使用Observable.create()
Observable<String> myStrings = Observable.create(emitter -> { emitter.onNext("apple"); emitter.onNext("bear"); emitter.onNext("change"); emitter.onComplete(); });
-
使用Observable.just()
Observable<String> myStrings = Observable.just("Alpha", "Beta", "Gamma", "Delta", "Epsilon");
-
从其他数据源创建,例如Observable.fromIterable()
,
Observable.range()Observers
可以通过实现
Observer
接口的方式去创建一个观察者,当然更常见的case是通过lambda表达式来创建一个观察者,就像之前用到的例子一样;注册的方式是通过调用Observerbale的
subscribe
方法Operators
只创建流和观察者并不能有什么太大的作用,大多时候我们需要通过操作符(Operator)来对流进行各种各样的操作才能使RP变得有实际意义
RxJava中提供了非常丰富的操作符,大致分为以下几类:
-
创建操作符,用于创建流,刚才我们已经用到了其中的几个,比如Create, Just, Range和Interval
-
变换操作符,用于将一个流变换成另一种形式,比如Buffer(将流中的元素打包转换成集合)、Map(对流中的每个元素执行一个函数),Window(将流中的元素拆分成不同的窗口再发射)
-
过滤操作符,过滤掉流中的部分数据以获取指定的数据元素,比如Filter、First、Distinct
-
组合操作符,将多个流融合成一个流,比如And、Then、Merge、Zip
-
条件/算术/聚合/转换操作符 … 起到各种运算辅助作用
-
自定义操作符,由用户自己创建
背压
所谓背压,是指异步环境中,生产者的速度大于消费者速度时,消费者反过来控制生产者速度的策略(也称为回压),这是一种流控的方式,可以更有效的利用资源、同时防止错误的雪崩
Throttling 节流类
通过操作符来调节Observable发射消息的速度,比如使用
sample()
来定期采样,并发出最后一个数据,或者使用throttleWithTimeout()
来丢弃超时的数据。但这样做会丢弃一部分数据,最终消费者拿不到完整的消息。Buffer & Window 缓冲和窗口类
使用缓冲
buffer()
和窗口window()
暂存那些发送速度过快的消息,等到消息发送速度下降的时候再释放它们。这主要应用于Observable发送速率不均匀的场景。Flux和Mono
-
Flux 和 Mono 是 Reactor 中的两个基本概念。Flux 表示的是包含 0 到 N 个元素的异步序列。在该序列中可以包含三种不同类型的消息通知:正常的包含元素的消息、序列结束的消息和序列出错的消息。当消息通知产生时,订阅者中对应的方法 onNext(), onComplete()和 onError()会被调用。
-
Mono 表示的是包含 0 或者 1 个元素的异步序列。该序列中同样可以包含与 Flux 相同的三种类型的消息通知。Flux 和 Mono 之间可以进行转换。对一个 Flux 序列进行计数操作,得到的结果是一个 Mono对象。把两个 Mono 序列合并在一起,得到的是一个 Flux 对象。
-
-
-
三、总结
今天大概了解了Reactive Programming的基本概念,详细运用还需要下来好好学习。