RxJava源码笔记(一)
前言
RxJava框架能简单高效地构建异步流,但是使用门槛较高。Java中实现异步的方式有很多,比如Thread类、Runnable以及Callable接口。但是他们直接使用起来相对没那么优雅,JDK1.5之前使用的Future类,以及之后的CompletableFuture类对异步任务的构建进行了优化。
RxJava框架在很多地方都有涉及,比如Netflix的Hystrix的框架,CouchBase的Java SDK,Vertx框架的构建异步任务也常用RxJava来优化避免回调地狱。
RxJava简介
名词解释
第一次听到这个名字的时候把RxJava听成了Ajax😅
R=Reactive x=Extensions Rx的意思是为了异步编程而做的响应式扩展(Reactive Extensions for Async Programming)。就是方便用户进行响应式的异步编程而创造的第三方库。因此Rx在很多语言上都有实现,比如js上实现的rxjs,基于Kotlin语言的RxKotlin,以及基于Java JVM实现的RxJava(笔记基于RxJava 2.x的版本)。
概念解释
RxJava基于观察者模式,存在如下几种角色
角色 | 角色功能 |
---|---|
被观察者(Observable ) | 产生事件 |
观察者(Observer ) | 响应事件并做出处理 |
事件(Event ) | 被观察者和观察者的消息载体 |
订阅(Subscribe ) | 连接被观察者和观察者 |
RxJava中的事件(Event)存在如下几种情况
事件类型 | 含义 | 说明 |
---|---|---|
onNext | 常规事件 | 被观察者可以发送无数个Next事件,观察者也可以接受无数个Next事件 |
onComplete | 结束事件 | 被观察者发送Complete事件后可以继续发送事件,观察者收到Complete事件后将不会接受其他任何事件 |
onError | 异常事件 | 被观察者发送Error事件后,其他事件将被终止发送,观察者收到Error事件后将不会接受其他任何事件 |
其中onComplete和onError之间是互斥的,一个发生了另一个就不会发生。
基本流程
比较核心的部分是订阅流程和线程切换流程。
订阅流程
下行
订阅(Subcribe)前需要构建数据流
// 利用create操作符创建一个被观察者(observable), observable0
Observable<String> observable0 = Observable.create(new ObservableOnSubscribe<String>() {
// 1.
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
// onNext设置每次向下游发射的数据
emitter.onNext("1");
emitter.onNext("2");
emitter.onNext("3");
}
});
// 利用map操作符在上游被观察者observable0上继续创建一个被观察者observable1
// map操作符表示对上游每一个onNext发射的数据("1","2","3")进行映射(apply方法)得到一个新的数据,构建新的流发射给下游
// 2.
Observable<String> observable1 = observable0.map(new Function<String, String>() {
@Override
public String apply(String s) throws Exception {
return s + "#";
}
});
// 同上map方法……
Observable<String> observable2 = observable1.map(new Function<String, String>() {
@Override
public String apply(String s) throws Exception {
return s + "*";
}
});
// 生成下游观察者observer,设置onNext, onError, onComplete等回调方法,
Observer<String> observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
// 当出发subscribe方法时候触发
System.out.println("onSubscribe");
}
@Override
public void onNext(String s) {
// 当上游observable1每次发射数据时候触发
System.out.println("onNext : " + s);
}
@Override
public void onError(Throwable e) {
// 当上游observable1每次发射数据异常时候触发(最多触发一次)
System.out.println("onError : " + e.toString());
}
@Override
public void onComplete() {
// 当上游observable1显示调用onComplete方法时候触发(最多触发一次),否则不触发
System.out.println("onComplete");
}
};
// 订阅observable2上游的数据流,响应上游每次发射的数据的事件
// 3.
observable2.subscribe(observer);
得到的结果是
onSubscribe
onNext : 1#*
onNext : 2#*
onNext : 3#*
接下来开始分析基本构建流程:
从1.处的Observable.create方法开始
Observable#create
public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
// 判空,对阅读没啥帮助,不用看
ObjectHelper.requireNonNull(source, "source is null");
return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
}
创建了一个ObservableCreate对象,这玩意看看是啥,
public final class ObservableCreate<T> extends Observable<T> {
final ObservableOnSubscribe<T> source;
public ObservableCreate(ObservableOnSubscribe<T> source) {
// new ObservableCreate<T>(source)时候将被观察者source传入,并设置为属性
this.source = source;
}
// 关键方法
@Override
protected void subscribeActual(Observer<? super T> observer) {
// 先省略
}
static final class CreateEmitter<T>
extends AtomicReference<Disposable>
implements ObservableEmitter<T>, Disposable {
// 先省略
}
// 忽略其他次要的代码……
}
原来ObservableCreate也是一个被观察者Observable,继承了Observable。
将这个ObservableCreate传入RxJavaPlugins.onAssembly,看看这个方法干了啥
// 设置钩子方法,默认null不设置,可以手动设置它去记录日志之类的
static volatile Function<? super Observable, ? extends Observable> onObservableAssembly;
// Calls the associated hook function.
public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {
Function<? super Observable, ? extends Observable> f = onObservableAssembly;
// 默认这里不执行,直接返回source
if (f != null) {
return apply(f, source);
}
return source;
}
配合注释发现没软用,这个方法啥都没干,将source原封不动返回了。
以上就是create方法在构建流中起到的功能:返回一个新的被观察者Observable, 并且设置我们自定义的source(ObservableOnSubscribe)作为成员变量。
接下来看看构建流的下一步,从2.处的observabl0.map方法开始
Observable#map
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
// 判空,不看
ObjectHelper.requireNonNull(mapper, "mapper is null");
// 同样的RxJavaPlugins.onAssembly啥都没干,下面等价于:
// return new ObservableMap<T, R>(this, mapper);
return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}
创建了一个ObservableMap对象,这玩意看看是啥,
public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {
final Function<? super T, ? extends U> function;
public ObservableMap(ObservableSource<T> source, Function<? super T, ? extends U> function) {
// 构造方法:同时将上游的observable0对象作为source参数,对每个元素的映射关系的function作为参数传入。
// 也就意味着下游observable会拥有上游observable的引用,方便后续订阅时候调用上游的subscribe()
super(source);
this.function = function;
}
// 关键方法
@Override
public void subscribeActual(Observer<? super U> t) {
// 方便后续订阅时候调用
source.subscribe(new MapObserver<T, U>(t, function));
}
static final class MapObserver<T, U> extends BasicFuseableObserver<T, U> {
final Function<? super T, ? extends U> mapper;
MapObserver(Observer<? super U> actual, Function<? super T, ? extends U> mapper) {
super(actual);
this.mapper = mapper;
}
// 忽略其他次要的代码……
}
abstract class AbstractObservableWithUpstream<T, U> extends Observable<U> implements HasUpstreamObservableSource<T>
ObservableMap继承自 AbstractObservableWithUpstream, AbstractObservableWithUpstream继承自Observable。所以ObservableMap也是一个被观察者Observable。
以上就是map方法在构建流中的功能:也是返回一个新的被观察者Observable。通过new ObservableMap<T, R>(this, mapper)可以看出,将上游(observable0)的Observable作为新的Observable的成员变量。
以此类推每次map或者flatMap等操作符运算都会构建一个新的Observable对象返回给下游。observable2的的构建和observable一样,这就就不写了。
包含关系图
以上是构建流之后的三个observable包含关系,可以看出,observable2包含了observable1,observable1包含了observable0。因此在后期订阅(subscribe方法)的时候,流可以从由外向里(由下游到上游)逐层调用对应的subscribe方法。
回溯
当触发3. observable2.subscribe时候将进行回溯,回溯的本质是将下游的订阅信息(observer观察者)回溯到上游observable中去,让最上游的observable0接收到订阅消息后将调用emitter.onNext方法依次将数据再由上向下observable0.onNext -> observable1.onNext -> observable2.onNext传递。
回溯流向图
从代码角度来看:observable2.subscribe将下游的观察者(observer)传入
public final void subscribe(Observer<? super T> observer) {
// 将下游观察者observer传给subscribeActual方法
/**
这里的最下游观察者是这一坨
Observer<String> observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
// 当出发subscribe方法时候触发
System.out.println("onSubscribe");
}
@Override
public void onNext(String s) {
// 当上游observable1每次发射数据时候触发
System.out.println("onNext : " + s);
}
@Override
public void onError(Throwable e) {
// 当上游observable1每次发射数据异常时候触发(最多触发一次)
System.out.println("onError : " + e.toString());
}
@Override
public void onComplete() {
// 当上游observable1显示调用onComplete方法时候触发(最多触发一次),否则不触发
System.out.println("onComplete");
}
};
**/
subscribeActual(observer);
// 省略其他无关代码
}
}
查看subscribeActual方法,发现是一个抽象方法,那么具体的实现在子类
protected abstract void subscribeActual(Observer<? super T> observer);
debug之后发现实现类是在ObservableMap类中的subscribeActual方法
@Override
public void subscribeActual(Observer<? super U> t) {
source.subscribe(new MapObserver<T, U>(t, function));
}
ObservableMap这个类似曾相识,在哪见过呢?原来在生成observable2的时候,observable1.map的时候创建的
new ObservableMap<T, R>(this, mapper);
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
// ……
// 生成observable2
return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}
所以就是observable2的subscribeActual方法。
subscribeActual方法传入了一个MapObserver对象,同时往该对象里传入下游观察者的observer和observable2内部的function。
再看看MapObserver类,他是ObservableMap(Observable)的内部类,也就是说一个Observable内往往也包含了对应观察者(observer)的内部类。
public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {
static final class MapObserver<T, U> extends BasicFuseableObserver<T, U> {
final Function<? super T, ? extends U> mapper;
MapObserver(Observer<? super U> actual, Function<? super T, ? extends U> mapper) {
// 设置下游observer为父类AbstractObservableWithUpstream中名字为downstream的变量
super(actual);
this.mapper = mapper;
}
@Override
public void onNext(T t) {
U v;
// 将上游发射的t数据通过observable1的map方法进行映射映射,并调用下游downstream(是一个observable)的onNext方法向下游传递
v = mapper.apply(t);
downstream.onNext(v);
}
}
就这样返回了一个拥有onNext等方法的观察者observer。
在 observable2的subscribeActual方法中调用source.subscribe(observer); 从前面的包含关系图中可以看出这里的source应该是observable1(同样地observable1中的source也应该是observable0)。因此在observable2中调用了observable1的subscribe方法并将observable2中生成的观察者作为参数向上传递。
现在到了observable1的subscribe方法,同样地,和observable2的subscribe方法一样,observable1先会在subscribe中调用subscribeActual方法,然后会到observable1具体子类ObservableMap调用subscribeActual方法,同样再new MapObserver<T, U>(t, function)返回一个observer1,再通过source的subscribe方法将observable1中生成的观察者observer1传回给observable0。
接下来到了observable0的subscribe方法, 到具体实现类ObservableCreate调用subscribeActual方法
public final class ObservableCreate<T> extends Observable<T> {
final ObservableOnSubscribe<T> source;
public ObservableCreate(ObservableOnSubscribe<T> source) {
this.source = source;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
// 这里的observer是下游传递上来的observer1
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
/**
这里的source是一开始crete里面的
new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("1");
emitter.onNext("2");
emitter.onNext("3");
}
}
**/
source.subscribe(parent);
}
static final class CreateEmitter<T>
extends AtomicReference<Disposable>
implements ObservableEmitter<T>, Disposable {
private static final long serialVersionUID = -3434801548987643227L;
final Observer<? super T> observer;
CreateEmitter(Observer<? super T> observer) {
this.observer = observer;
}
@Override
public void onNext(T t) {
// 相当于调用了ObservableEmitter的onNext方法。
observer.onNext(t);
}
// ……
}
subscribeActual里调用了source.subscribe方法,这里的source就是我们一开始create方法里的lambda参数。此时subscribe来到了
emitter.onNext(“1”);这里的emitter就是现在ObservableCreate中的内部类CreateEmitter,所以相当于调用了ObservableEmitter的onNext方法。
@Override
public void onNext(T t) {
// 相当于调用了ObservableEmitter的onNext方法。
observer.onNext(t);
}
下行流动
onNext中调用了从最下游来到最上游的observer的onNext方法。
此时数据开始流动:
下行流动才是真正数据开始处理的时机,体现了流惰性处理的特性。
小结
笔记(一)中介绍了RxJava的基本概念,背景等,以及订阅的基本流程。
订阅的基本流程分为3个阶段
- 下行:基于操作符(map, create等)向下构建流,本质是向下游传递observable被观察者对象。
- 回溯:当发生订阅的时候触发,本质是向上游传递observer观察者对象。
- 下行流动:这是真正触发运算的时机,本质是向下游传递并处理数据。上游通过observer的onNext事件将数据向下流转运算得到最终结果。
未来计划
接下来的笔记写点RxJava线程切换调度的源码,背压以及常见操作符比如flatMap, map,take、zip的源码。