RxJava2 原始碼解析及設計思想

Yuloran發表於2019-01-03

專案經驗,如需轉載,請註明作者:Yuloran (t.cn/EGU6c76)

前言

本文簡析 RxJava2subscribeOnzip 操作符。

術語解釋

Single.just().map().flatMap().subscribeOn().observeOn().subscribe();
複製程式碼

上述程式碼中,Singlesubscribe() 之間的都稱為 操作符,想像一下自己就是其中一個 操作符,那麼位於左邊的便稱為 上游,位於右邊的則稱為 下游,故上下游其實是相對的。

原始碼分析指南

由於 RxJava 是鏈式呼叫,鏈條長度沒有限制,所以原始碼分析需要技巧,直接從頭看到尾,容易看的頭暈。所以建議先寫一個『最短的呼叫鏈』去分析,然後舉一反三,推測其設計思想(仔細想想就知道,那麼多操作符,肯定不需要每個都去分析,也不現實,所以只要理解其設計思想就行了)。

首先,我們需要明確每一次操作符呼叫的返回型別是什麼:subscribe() 左邊都是觀察者的上游,而觀察者的上游肯定是被觀察者。所以每一次操作符呼叫的返回型別都是被觀察者(而且每次都返回一個新的被觀察者,內部持有對上一個觀察者的引用)。鑑於 RxJava 的被觀察者型別較多,有:

背壓:上游資料發射太快,下游來不及處理,導致緩衝區溢位(類比我國人民都知道的水缸進水、放水問題)

本文僅以 io.reactivex.Single為例進行分析,其他型別舉一反三即可,此處先給出物件引用關係圖,根據此圖即可推出函式呼叫軌跡:

RxJava2 原始碼解析及設計思想

原始碼分析都寫在註釋裡了,subscribeOn 操作符是對 java 併發框架和 Android Handler 的封裝,zip 操作符則是利用 java 原子類實現的。

解析 subscribeOn

demo

        // Case2: 在非UI執行緒執行並關注結果
        Single.fromCallable(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return generateRandom();
            }
        }).subscribeOn(Schedulers.io()).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Logger.d(TAG, "test: accept(Integer integer) invoked on %s", Thread.currentThread().getName());
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                Logger.d(TAG, "test: accept(Throwable throwable) invoked on %s", Thread.currentThread().getName());
            }
        });
複製程式碼

fromCallable(Callable callable) [-> Single.java]

    public static <T> Single<T> fromCallable(final Callable<? extends T> callable) {
        ObjectHelper.requireNonNull(callable, "callable is null");
        // RxJavaPlugins 裡是全域性鉤子函式,分析原始碼時無視即可,此處就是返回 SingleFromCallable
        return RxJavaPlugins.onAssembly(new SingleFromCallable<T>(callable));
    }
複製程式碼

RxJavaPlugins 裡是全域性鉤子函式,無需關注

SingleFromCallable [-> SingleFromCallable.java]

// 注意繼承自 Single,而 Single 實現了 SingleSource 介面,所以也繼承了 subscribe() 方法
public final class SingleFromCallable<T> extends Single<T> {
    // 回撥函式
    final Callable<? extends T> callable;

    public SingleFromCallable(Callable<? extends T> callable) {
        // 儲存為全域性變數
        this.callable = callable;
    }

    @Override
    protected void subscribeActual(SingleObserver<? super T> observer) {
        // 一個 run() 方法體為空的 RunnableDisposable 物件,用來取消訂閱
        Disposable d = Disposables.empty();
        // 呼叫下游(本示例此處為SubscribeOnObserver)的 onSubscribe()
        observer.onSubscribe(d);

        // 已取消訂閱的,直接返回,不會發射任何值
        if (d.isDisposed()) {
            return;
        }

        T value;
        try {
            // 呼叫 callable.call() 獲取值
            value = ObjectHelper.requireNonNull(callable.call(), "The callable returned a null value");
        } catch (Throwable ex) {
            // 捕獲所有異常,所以使用 rxjava 時,自己寫的方法收不到異常通知,需訂閱一個 Consumer<Throwable>
            Exceptions.throwIfFatal(ex);
            if (!d.isDisposed()) {
                // 發射一個 error 事件給下游
                observer.onError(ex);
            } else {
                RxJavaPlugins.onError(ex);
            }
            return;
        }

        if (!d.isDisposed()) {
            // 發射一個 success 事件給下游
            observer.onSuccess(value);
        }
    }
}
複製程式碼

subscribeOn(Scheduler scheduler) [-> Single.java]

    public final Single<T> subscribeOn(final Scheduler scheduler) {
        ObjectHelper.requireNonNull(scheduler, "scheduler is null");
        // 返回 SingleSubscribeOn
        return RxJavaPlugins.onAssembly(new SingleSubscribeOn<T>(this, scheduler));
    }
複製程式碼

SingleSubscribeOn [-> SingleSubscribeOn.java]

// 注意繼承自 Single,而 Single 實現了 SingleSource 介面,所以也繼承了 subscribe() 方法
public final class SingleSubscribeOn<T> extends Single<T> {
    // 上游
    final SingleSource<? extends T> source;
    // 執行緒排程器
    final Scheduler scheduler;

    public SingleSubscribeOn(SingleSource<? extends T> source, Scheduler scheduler) {
        // 儲存上游為 this.source
        this.source = source;
        // 儲存執行緒排程器為 this.scheduler
        this.scheduler = scheduler;
    }

    @Override
    protected void subscribeActual(final SingleObserver<? super T> s) {
        // 將下游和上游包裝為 SubscribeOnObserver
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s, source);
        // 呼叫下游的 onSubscribe(),此時還沒有切換執行緒,所以 onSubscribe() 是在原執行緒執行的
        s.onSubscribe(parent);
        // 將 SubscribeOnObserver 扔到執行緒排程器中執行,此處就是 IoScheduler,內部實現基於 jdk 的 ExecutorService、FutureTask 和 Future
        Disposable f = scheduler.scheduleDirect(parent);
        // 將排程器返回的 Disposable(一個實現了 Disposable 和 Runnable 介面的 DisposeTask) 物件設定給 SubscribeOnObserver 的 task,用來取消訂閱、中斷執行緒執行
        parent.task.replace(f);
    }

    // 繼承自 AtomicReference,實現了 SingleObserver、Disposable、Runnable介面
    // SingleObserver:當作下游
    // Disposable:傳給下游以便下游用來取消訂閱
    // Runnable:用來提交給 ExecutorService
    static final class SubscribeOnObserver<T> extends AtomicReference<Disposable>
    implements SingleObserver<T>, Disposable, Runnable {
        private static final long serialVersionUID = 7000911171163930287L;
        // 下游
        final SingleObserver<? super T> actual;
        // 用來取消訂閱、中斷執行緒執行
        final SequentialDisposable task;
        // 上游
        final SingleSource<? extends T> source;

        SubscribeOnObserver(SingleObserver<? super T> actual, SingleSource<? extends T> source) {
            // 將下游儲存為 this.actual
            this.actual = actual;
            // 將上游儲存為 this.source
            this.source = source;
            // 一個繼承自 AtomicReference 實現了 Disposable 介面的物件,用來取消訂閱、中斷執行緒執行
            this.task = new SequentialDisposable();
        }

        @Override
        public void onSubscribe(Disposable d) {
            // 因為繼承自 AtomicRefrence,此處將取消訂閱的控制程式碼(本示例中此處為 Disposables.empty())設定給內部的物件引用,用於取消對上游的訂閱
            DisposableHelper.setOnce(this, d);
        }

        @Override
        public void onSuccess(T value) {
            // 上游呼叫 observer.onSuccess() 時,會呼叫到這裡,此處繼續呼叫下游的 onSuccess() 將值向下傳遞
            actual.onSuccess(value);
        }

        @Override
        public void onError(Throwable e) {
            // 上游呼叫 observer.onError() 時,會呼叫到這裡,此處繼續呼叫下游的 onError() 將錯誤向下傳遞
            actual.onError(e);
        }

        @Override
        public void dispose() {
            // 取消對上游的訂閱
            DisposableHelper.dispose(this);
            // 中斷執行緒執行
            task.dispose();
        }

        @Override
        public boolean isDisposed() {
            return DisposableHelper.isDisposed(get());
        }

        @Override
        public void run() {
            // 線上程池中執行 source.subscribe(),本示例會觸發:
            // SingleFromCallable.subscribe()->
            // SingleFromCallable.suscribeActual()->
            // this.onSuccess(callable.call())
            source.subscribe(this);
        }
    }
}
複製程式碼

subscribe() [-> Single.java]

    public final Disposable subscribe(final Consumer<? super T> onSuccess, final Consumer<? super Throwable> onError) {
        ObjectHelper.requireNonNull(onSuccess, "onSuccess is null");
        ObjectHelper.requireNonNull(onError, "onError is null");

        // 將 successConsumer、throwableConsumer 包裝成 ConsumerSingleObserver,作為觀察者
        ConsumerSingleObserver<T> s = new ConsumerSingleObserver<T>(onSuccess, onError);
        // 呼叫 subscribe(SingleObserver subscriber)
        subscribe(s);
        // ConsumerSingleObserver 實現了 Disposable 介面,持有它,可以用來取消訂閱 
        return s;
    }
複製程式碼

subscribe(SingleObserver subscriber) [-> Single.java]

    public final void subscribe(SingleObserver<? super T> subscriber) {
        ObjectHelper.requireNonNull(subscriber, "subscriber is null");
        subscriber = RxJavaPlugins.onSubscribe(this, subscriber);
        ObjectHelper.requireNonNull(subscriber, "subscriber returned by the RxJavaPlugins hook is null");

        try {
            // 繼續呼叫抽象方法 subscribeActual(SingleObserver subscriber),即呼叫子類的 subscribeActual(SingleObserver subscriber)
            // 本示例中,此處子類為 SingleSubscribeOn,原始碼分析見上方
            subscribeActual(subscriber);
        } catch (NullPointerException ex) {
            throw ex;
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            NullPointerException npe = new NullPointerException("subscribeActual failed");
            npe.initCause(ex);
            throw npe;
        }
    }
複製程式碼

ConsumerSingleObserver [->ConsumerSingleObserver .java]

public final class ConsumerSingleObserver<T> extends AtomicReference<Disposable>
implements SingleObserver<T>, Disposable, LambdaConsumerIntrospection {
    private static final long serialVersionUID = -7012088219455310787L;
    // successConsumer
    final Consumer<? super T> onSuccess;
    // throwableConsumer
    final Consumer<? super Throwable> onError;

    public ConsumerSingleObserver(Consumer<? super T> onSuccess, Consumer<? super Throwable> onError) {
        // 將 successConsumer 儲存為全域性變數 this.onSuccess
        this.onSuccess = onSuccess;
        // 將 throwableConsumer 儲存為全域性變數 this.onError
        this.onError = onError;
    }

    @Override
    public void onError(Throwable e) {、
        // 最後設定為已取消訂閱
        lazySet(DisposableHelper.DISPOSED);
        try {
            // 回撥 throwableConsumer
            onError.accept(e);
        } catch (Throwable ex) {
            Exceptions.throwIfFatal(ex);
            RxJavaPlugins.onError(new CompositeException(e, ex));
        }
    }

    @Override
    public void onSubscribe(Disposable d) {
        // 本示例中,d 為 SubscribeOnObserver
        DisposableHelper.setOnce(this, d);
    }

    @Override
    public void onSuccess(T value) {
        // 最後設定為已取消訂閱
        lazySet(DisposableHelper.DISPOSED);
        try {
            // 回撥 successConsumer
            onSuccess.accept(value);
        } catch (Throwable ex) {
            // 異常被 rxjava 捕獲,所以自己寫的 successConsumer 收不到異常
            Exceptions.throwIfFatal(ex);
            RxJavaPlugins.onError(ex);
        }
    }

    @Override
    public void dispose() {
        // 取消訂閱
        DisposableHelper.dispose(this);
    }

    @Override
    public boolean isDisposed() {
        return get() == DisposableHelper.DISPOSED;
    }

    @Override
    public boolean hasCustomOnError() {
        return onError != Functions.ON_ERROR_MISSING;
    }
}
複製程式碼

時序圖

Sequence Diagram

解析 zip

demo

        // Case6: 併發讀取不同資料來源,轉換成同型別後,合併
        Single<IBook> novel = Single.fromCallable(new Callable<Novel>() {
            @Override
            public Novel call() throws Exception {
                return getNovel();
            }
        }).map(new Function<Novel, IBook>() {
            @Override
            public IBook apply(Novel novel) throws Exception {
                return new NovelAdapter(novel);
            }
        }).subscribeOn(Schedulers.io());

        Single<IBook> rxJava2Tutorial = Single.fromCallable(new Callable<RxJava2Tutorial>() {
            @Override
            public RxJava2Tutorial call() throws Exception {
                return getRxJava2Tutorial();
            }
        }).map(new Function<RxJava2Tutorial, IBook>() {
            @Override
            public IBook apply(RxJava2Tutorial rxJava2Tutorial) throws Exception {
                return new RxJava2TutorialAdapter(rxJava2Tutorial);
            }
        }).subscribeOn(Schedulers.io());

        // 注意此處呼叫的是合併兩個 SingleSource 的方法,zip 操作符的過載方法很多,從 2~9 都有,相應的變換函式也有從 2~9,無語啊~
        Single.zip(novel, rxJava2Tutorial, new BiFunction<IBook, IBook, List<IBook>>() {
            @Override
            public List<IBook> apply(IBook iBook, IBook iBook2) throws Exception {
                List<IBook> books = new ArrayList<>(2);
                books.add(iBook);
                books.add(iBook2);
                return books;
            }
        }).subscribe(new Consumer<List<IBook>>() {
            @Override
            public void accept(List<IBook> iBooks) throws Exception {
                Logger.d(TAG, "test: books are " + iBooks);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                Logger.d(TAG, "test: get books error.", throwable);
            }
        });
複製程式碼

上述程式碼分別讀取 NovelRxJava2Tutorial 兩種不同型別書籍,再分別轉化為 IBook 型別,然後新增到同一陣列中,最後發射給下游。

zip(SingleSource source1, SingleSource source2, BiFunction zipper) [-> Single.java]

    public static <T1, T2, R> Single<R> zip(
            SingleSource<? extends T1> source1, SingleSource<? extends T2> source2,
            BiFunction<? super T1, ? super T2, ? extends R> zipper
     ) {
        ObjectHelper.requireNonNull(source1, "source1 is null");
        ObjectHelper.requireNonNull(source2, "source2 is null");
        return zipArray(Functions.toFunction(zipper), source1, source2);
    }
複製程式碼

toFunction(BiFunction f) [-> Functions.java]

    public static <T1, T2, R> Function<Object[], R> toFunction(final BiFunction<? super T1, ? super T2, ? extends R> f) {
        ObjectHelper.requireNonNull(f, "f is null");
        // 注意因為上面呼叫的是合併兩個 SingleSource 的方法,所以這裡呼叫的就是 Array2Func,2表示合併個數,像這樣的還有 Array3Func、Array4Func、... Array9Func
        // 作用就是把多引數的 BiFunction 統一轉化為一個引數(Object[])的 Function 物件,呼叫的時候再把引數從 Object[] 裡取出來即可
        return new Array2Func<T1, T2, R>(f);
    }
複製程式碼

Array2Func [-> Functions::Array2Func]

    static final class Array2Func<T1, T2, R> implements Function<Object[], R> {
        final BiFunction<? super T1, ? super T2, ? extends R> f;

        Array2Func(BiFunction<? super T1, ? super T2, ? extends R> f) {
            this.f = f;
        }

        @SuppressWarnings("unchecked")
        @Override
        public R apply(Object[] a) throws Exception {
            if (a.length != 2) {
                throw new IllegalArgumentException("Array of size 2 expected but got " + a.length);
            }
            // 從 Object[] 中取出實參,然後呼叫實際的合併函式
            return f.apply((T1)a[0], (T2)a[1]);
        }
    }
複製程式碼

zipArray(Function zipper, SingleSource... sources) [-> Single.java]

    public static <T, R> Single<R> zipArray(Function<? super Object[], ? extends R> zipper, SingleSource<? extends T>... sources) {
        ObjectHelper.requireNonNull(zipper, "zipper is null");
        ObjectHelper.requireNonNull(sources, "sources is null");
        if (sources.length == 0) {
            return error(new NoSuchElementException());
        }
        return RxJavaPlugins.onAssembly(new SingleZipArray<T, R>(sources, zipper));
    }
複製程式碼

SingleZipArray [-> SingleZipArray.java]

// 繼承自 Single,而 Single 實現了 SingleSource 介面,所以也繼承了 subscribe() 方法
public final class SingleZipArray<T, R> extends Single<R> {
    // 用來儲存要合併的 SingleSource
    final SingleSource<? extends T>[] sources;
    // 用來儲存合併函式
    final Function<? super Object[], ? extends R> zipper;

    public SingleZipArray(SingleSource<? extends T>[] sources, Function<? super Object[], ? extends R> zipper) {
        // 將 SingleSource 儲存為 this.sources
        this.sources = sources;
        // 將合併函式儲存為 this.zipper
        this.zipper = zipper;
    }

    // 通過上面 subscribeOn 的原始碼分析可知,呼叫 subscribe() 時,便會呼叫到上游的 subscribeActual()
    // 此處的 observer 同樣也是 ConsumerSingleObserver
    @Override
    protected void subscribeActual(SingleObserver<? super R> observer) {
        SingleSource<? extends T>[] sources = this.sources;
        int n = sources.length;
        // 本示例合併的 SingleSource 個數為 2,即 n=2
        if (n == 1) {
            sources[0].subscribe(new SingleMap.MapSingleObserver<T, R>(observer, new SingletonArrayFunc()));
            return;
        }

        // 將 ConsumerSingleObserver、SingleSource個數、合併函式封裝為 ZipCoordinator,用來等待所有 
        // SingleSource 都處理完,然後對其發射的值應用合併函式 
        ZipCoordinator<T, R> parent = new ZipCoordinator<T, R>(observer, n, zipper);
        // 呼叫 ConsumerSingleObserver 的 onSubscribe()
        observer.onSubscribe(parent);
        // 一個 for 迴圈,挨個呼叫 SingleSource 的 subscribe(),觸發生產者開始生產
        for (int i = 0; i < n; i++) {
            if (parent.isDisposed()) {
                return;
            }

            SingleSource<? extends T> source = sources[i];

            if (source == null) {
                parent.innerError(new NullPointerException("One of the sources is null"), i);
                return;
            }

            source.subscribe(parent.observers[i]);
        }
    }
    ......
}
複製程式碼

ZipCoordinator [-> SingleZipArray::ZipCoordinator]

    // 合併函式協調器,注意繼承自 AtomicInteger,以便採用計數法檢測是否所有的 SingleSource 都發射完畢
    static final class ZipCoordinator<T, R> extends AtomicInteger implements Disposable {
        private static final long serialVersionUID = -5556924161382950569L;
        // 儲存下游觀察者,本示例此處為 ConsumerSingleObserver
        final SingleObserver<? super R> actual;
        // 儲存合併函式
        final Function<? super Object[], ? extends R> zipper;
        // SingleZipArray 的直接觀察者,用來分別接收每個 SingleSource 發射的結果
        // 每收到一個值 (即每回撥一次 ZipSingleObserver 的 onSuccess()),計數值-1,直至計數值為0,說明全部發射完畢
        final ZipSingleObserver<T>[] observers;
        // 儲存每個 SingleSource 發射的結果
        final Object[] values;

        @SuppressWarnings("unchecked")
        ZipCoordinator(SingleObserver<? super R> observer, int n, Function<? super Object[], ? extends R> zipper) {
            // 因為繼承自 AtomicInteger,所以呼叫父類構造器,設定計數值
            super(n);
            // 將下游觀察者 ConsumerSingleObserver 儲存為 this.actual,用來接收合併後的結果
            this.actual = observer;
            // 將合併函式儲存為 this.zipper
            this.zipper = zipper;
            // 根據 SingleSource 的個數,生成相應個數的 SingleObserver,然後儲存為 this.observers
            ZipSingleObserver<T>[] o = new ZipSingleObserver[n];
            for (int i = 0; i < n; i++) {
                o[i] = new ZipSingleObserver<T>(this, i);
            }
            this.observers = o;
            // 根據 SingleSource 的個數,生成相應長度的 Object[],用來儲存它們發射的結果
            this.values = new Object[n];
        }

        @Override
        public boolean isDisposed() {
            return get() <= 0;
        }

        @Override
        public void dispose() {
            if (getAndSet(0) > 0) {
                for (ZipSingleObserver<?> d : observers) {
                    d.dispose();
                }
            }
        }

        // 上游呼叫 ZipSingleObserver::onSuccess() 時,便會呼叫該方法,觸發計數值-1
        void innerSuccess(T value, int index) {
            values[index] = value;
            // 判斷計數值是否已減至零
            if (decrementAndGet() == 0) {
                // 計數值為0,說明 SingleSource 全部發射完畢,可以呼叫合併函式了
                R v;
                try {
                    // 呼叫合併函式,獲得合併後的結果
                    v = ObjectHelper.requireNonNull(zipper.apply(values), "The zipper returned a null value");
                } catch (Throwable ex) {
                    Exceptions.throwIfFatal(ex);
                    actual.onError(ex);
                    return;
                }
                // 將合併後的結果發射給下游,即 ConsumerSingleObserver 
                actual.onSuccess(v);
            }
        }

        void disposeExcept(int index) {
            ZipSingleObserver<T>[] observers = this.observers;
            int n = observers.length;
            for (int i = 0; i < index; i++) {
                observers[i].dispose();
            }
            for (int i = index + 1; i < n; i++) {
                observers[i].dispose();
            }
        }

        void innerError(Throwable ex, int index) {
            if (getAndSet(0) > 0) {
                disposeExcept(index);
                actual.onError(ex);
            } else {
                RxJavaPlugins.onError(ex);
            }
        }
    }
複製程式碼

ZipSingleObserver [-> SingleZipArray::ZipSingleObserver]

    // 用來接受 SingleSource 發射的結果 
    static final class ZipSingleObserver<T> extends AtomicReference<Disposable>
    implements SingleObserver<T> {
        private static final long serialVersionUID = 3323743579927613702L;
        // zip 協調器,用來觸發計數值-1、計數值為0時呼叫合併函式併發射合併結果
        final ZipCoordinator<T, ?> parent;
        // 接受第幾個 SingleSource 的結果
        final int index;

        ZipSingleObserver(ZipCoordinator<T, ?> parent, int index) {
            this.parent = parent;
            this.index = index;
        }

        public void dispose() {
            DisposableHelper.dispose(this);
        }

        @Override
        public void onSubscribe(Disposable d) {
            DisposableHelper.setOnce(this, d);
        }

        @Override
        public void onSuccess(T value) {
            // SingleSource 發射結果時,呼叫到這裡
            // 呼叫 ZipCoordinator::innerSuccess()
            parent.innerSuccess(value, index);
        }

        @Override
        public void onError(Throwable e) {
            // SingleSource 發射錯誤時,呼叫到這裡
            // 呼叫 ZipCoordinator::innerError
            parent.innerError(e, index);
        }
    }
複製程式碼

總結

類圖

Class Diagram

設計思想

函式呼叫軌跡

除了最上層的被觀察者和最下層的觀察者,中間的 Single 子類必有一與之對應的 SingleObserver 實現類,總結起來就是:

  • 我的下游的下游不是我的下游
  • 我的上游的上游不是我的上游
  • 我只能訪問我的直接上游和直接下游

嗯,這大概可以起名叫 可非同步執行的責任鏈模式。別搜了,這名字是我自己想的!

完整 demo 地址

相關文章