-
RxJava用来干什么
RxJava is a Java VM implementation of ReactiveX (Reactive Extensions): a library for composing asynchronous and event-based programs by using observable sequences.
简单来说,RxJava就是用来处理回调的,使用观察者模式来传递调用回溯,究其根源也就是使用普通的接口回调方式,更奇妙的是,它还使用了装饰模式来封装一层层回调,通过源码,我们才能体会它优雅的链式调用背后真正的美。
-
原理概述
拿一个链式调用的例子来梳理RxJava的原理:
Flowable.range(0, 10).doOnNext(System.out::println).all(integer -> integer < 5). blockingSubscribe(success -> System.out.println("Success: " + success));
range()、doOnNext()、all()三个方法都会产生一个Flowable的子类对象。
来看看range方法:
可以看到,count不能小于0且不能大于最大整数,并且针对没有元素、只有一个元素和不止一个元素三种情况分别返回三个不同的Flowable子类对象。empty()方法会返回一个FlowableEmpty(),just()会返回一个FlowableJust(),大于一个的会返回一个FlowableRange()。
这里我们先随便以其中的FlowableRange为例来看,那接下来就是FlowableRange().doOnNext方法了:
这个方法是父类Flowable里面的方法,实际上又走到了doOnEach方法里面:
onNext就是我们外面传入的lambda形式表示的Consumer对象,后面的三个参数分别是出现错误时、完成时、终止时的处理接口,这里因为没用到先不说,只要知道是构造了空的实例就好。这些参数都不能是null,最后返回了一个FlowableDoOnEach对象,接下来就用这个对象调用all方法:
参数Predicate(断言)是用来判定条件的,构造了一个含有这个条件的FlowableAllSingle对象。
到这里,可以看出来这个链式调用就是一步步的把一开始的Flowable子类对象一步步封装的过程,方式就是通过每个装饰对象的构造方法和前后的Flowable类型实例联系在一起:
new FlowableRange(0,10)把传入的start(这里是0)和count(这里是10)保存
new FlowableDoOnEach(this,onNext)把FlowableRange对象和System.out::println(Consumer实例)保存
new FlowableAllSingle(this,predicate)把FlowableDoOnEach对象和integer -> integer < 5(Predicate实例)保存
最后调用的方法就是开启往回回溯调用,看一下最后的Single类里的blockingSubscribe方法(其实通常调用subscribe方法就可以,这里之所以用blockingSubscribe方法是因为它涵盖了subscribe方法,不同的是blockingSubscribe方法会多一个observer.blockingConsume的调用,可以看到blockingSubscribe的onSuccess参数交给了它,因为在前面的操作完成后才会调用,至于怎么做的后面会讲到):
现在的重心到了subscribe方法里面:
这里的observer经过了一层RxJavaPlugins.onSubscribe(this,observer)的操作,前面链式装饰的时候也看到过这个RxJavaPlugins,你可以把它看成是一个全局的配置类,我们前面的onAssembly方法:
可以看到source会通过一个叫做onFlowableAssembly的对象处理一下再返回,这个onFlowableAssembly对象是一个静态的volatile(为了并发需要)变量:
@Nullable static volatile Function<? super Flowable, ? extends Flowable> onFlowableAssembly;
所以如果你通过onFlowableAssembly的set方法事先设置了,那么只要你的装饰对象是Flowable类型,构造的时候就会先调用这个对象处理一下。同样RxJavaPlugins.onSubscribe方法也一样,如果设置了则每次subscribe的时候都会先调用。
回到主线,try块里会调用subscribeActual方法,这个方法是Single里的abstract方法,所以这里的调用其实是在子类调用的,那这里的子类也就是FlowableAllSingle,找到它里面的subscribeActual方法看一下:
其中的observer就是前面的BlockingMultiObserver对象,source就是链式创建它的FlowableDoOnEach对象,调用subscribe方法同样会调用FlowableDoOnEach的subscribeActual方法,传入一个构造的AllSubscriber对象:
observer交给了AllSubscriber,赋值给了downstream,注意这个词是下游的意思,结合链式调用,这个词很形象。
FlowableDoOnEach的subscribeActual方法:
也是一样的,只不过这里针对不同的Subscriber实例构造不一样的往上游传递的Subscriber,因为这里的AllSubscriber不是ConditionalSubscriber类型,所以会走else分支,向其上游FlowableRange的subscribeActual方法传递一个DoOnEachSubscriber对象,s就是AllSubscriber,onNext就是Consumer对象(这里是System.out::println):
这里和上面不同,它没有source,所以这里就是向上游传递的终点,现在开始往下游传递,传递的对象是一个RangeSubscription,所以现在回到DoOnEachSubscriber的onSubscribe方法里,但是在DoOnEachSubscriber里没找到这个方法,于是我们在其父类BasicFuseableSubscriber里找到了它:
首先检查工作SubscriptionHelper.validate()代码如下:
这里就是要求当前操作的next不能为空,并且upstream要为空,若不为空说明之前还有未完成的操作,就把当前的next取消并在reportSubscriptionSet里面抛出"Subscription already set!"异常。upstream就是在这里赋值的,然后关键代码就是downstream.onSubscribe(this),这里的downstream是构造方法传进来的,所以也就是AllSubscriber,所以这里的onSubscribe方法就是AllSubscriber里面的:
同样也是上面类似的操作,到了BlockingMultiObserver的onSubscribe()方法里:
看起来这趟传递就是把一系列Subscription赋给相应的upstream关联起来,然后调用s.request方法开始沿着关联的upstream再往上回溯,那这趟回溯是做什么的呢,s也就是之前的BasicFuseableSubscriber,它的request调用了upstream的request方法,upstream也就是FlowableRange的subscribeActual里创建的RangeSubscription对象,在其父类BaseRangeSubscription里面找到了request方法:
传递的n是Long.MAX_VALUE,SubscriptionHelper.validate(n)要求n不能小于0,如果是最大值Long.MAX_VALUE则使用fastPath否则使用slowPath,我们这里n是Long.MAX_VALUE,所以看一下fastPath():
用一个for循环把index和end之间的整数依次传递给downstream的onNext,最后往下调用onComplete直到最后一个downstream的onComplete执行完成,在这个过程中调用onNext和onComplete之前都要判断订阅是否已经被取消了,若已取消则不继续操作了。onNext又怎么做的呢?这里的downstream显然是DoOnEachSubscriber:
这里的sourceMode是NONE(0),所以会走try-catch,先调用onNext.accept,即System.out.println(t),然后继续调用它的下游downstream的onNext方法,也就是AllSubscriber:
这里调用predicate.test(t)验证,即判断t<5?如果过程中发生了错误则链式通知上游依次取消并执行onError回调,如果条件满足则结束此次调用,再次回到fastPath中的for循环中执行下一次传递调用,如果不满足则结束for循环,注意如果拿这个例子来说,range(0,10)根据条件t<5会输出0,1,2,3,4,5,之所以会输出5是因为调用是根据链式调用顺序执行,所以会先执行println(5)再判断5满不满足继续循环。
执行完成最终都会执行到最后的downstream的onSuccess中,不同的是,通过顺利执行完fastPath的onSuccess传递的是true,而因条件或者错误canceled的传递的是false,BlockingMultiObserver的onSuccess如下:
其父类中countDown方法调用如下:
public void countDown() { sync.releaseShared(1); }
sync在构造的时候初始化的:
public BlockingMultiObserver() { super(1); }
sync.releaseShared(1)方法在Sync的父类AbstractQueuedSynchronizer中:
tryReleaseShared是上面Sync重写的,主要就是取当前的state值,若是0则返回false表示没什么可释放的了,若不是0则判断减1后的值是否是0,不是的话也不执行release操作,总之就是state只能是0或1,而且释放前只能是1。看看doReleaseShared操作:
其实这里会直接走到break,head是null,原因在于之前我们的链式调用和blockingSubscribe是在同一个线程中同步调用的,所以调用的blockingSubscribe中subscribe是在observer.blockingConsume之前调用的,而设置head的代码在blockingConsume中的await中的后续操作设置的:
最后有错误则onError.accept,没有就onSuccess.accept,即success -> System.out.println("Success: " + success),此时success是false。最后的输出结果是:
如果subscribe内部有新建线程执行的耗时工作时,那么observer.blockingConsume就不会等到subscribe内部线程工作执行完,那么此时会先执行await(因为初始化时sync设置了state为1,所以getCount是!=0),await最终处理代码:
addWaiter中做的工作就是创建head和tail,并把head的next指向tail,tail的prev指向head,最后返回tail(关于Unsafe代码(U)可以看sun.misc.Unsafe源码解析):
再回到doAcquireSharedInterruptibly方法,拿到的node就是tail,for循环中,node.predecessor()方法取到head(我们这里因为node是tail,tail的prev是head),所以进入if(p==head)内,调用sync.tryAcquireShared方法,此时getState()还是1,所以tryAcquireShared返回-1,所以这个for循环此时不会跳出,达到了block的目的,现在使程序继续的关键就是让state为0从而让sync.tryAcquireShared返回1。那么假设我们的subscribe中的执行逻辑在另外的线程中完成了,则会调用BlockMultiObserver的onSuccess方法,它会调用countdown(),其中又调用了上面士图中的sync.releaseShared(1),从sync.releaseShared(1)方法中可以看到如果当前state是1,则减1后会变成0并返回true,从而执行doReleaseShared方法,doReleaseShared里面一开始head.waitStatus是0,之后变成Node.PROPAGATE(-3),此时就在这里一直循环跳不出来,因为之前执行过tryReleaseShared,所以此时state是0,从而doAcquireSharedInterruptibly那边的for循环可以走setHeadAndPropagate了:
这里把tail(传进来的node就是tail)变成了head,因为propagate是1且tail的next是null(未设置过),所以也会走doReleaseShared方法,它走的这个doReleaseShared方法因为不满足h!=tail且h==head,所以跳出循环结束调用,同时countdown调用的doReleaseShared方法再次循环时也会因为此条件跳出循环,至此,blockingConsume可以走完,程序结束。
RxJava原理分析
最新推荐文章于 2023-01-18 11:08:53 发布