2024年Java最全RxJava2 源码解析(二),Java组件化开发教程

难道这样就够了吗?不,远远不够!

提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。

备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记

我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。

今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!

阿里一面就落马,恶补完这份“阿里面试宝典”后,上岸蚂蚁金服

阿里一面就落马,恶补完这份“阿里面试宝典”后,上岸蚂蚁金服

image.png

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

例子如下,源头Observable发送的是String类型的数字,利用map转换成int型,最终在终点Observer接受到的也是int类型数据。:

final Observable testCreateObservable = Observable.create(new ObservableOnSubscribe() {

@Override

public void subscribe(ObservableEmitter e) throws Exception {

e.onNext(“1”);

e.onComplete()

}

});

Observable map = testCreateObservable.map(new Function<String, Integer>() {

@Override

public Integer apply(String s) throws Exception {

return Integer.parseInt(s);

}

});

map.subscribe(new Observer() {

@Override

public void onSubscribe(Disposable d) {

Log.d(TAG, “onSubscribe() called with: d = [” + d + “]”);

}

@Override

public void onNext(Integer value) {

Log.d(TAG, “onNext() called with: value = [” + value + “]”);

}

@Override

public void onError(Throwable e) {

Log.d(TAG, “onError() called with: e = [” + e + “]”);

}

@Override

public void onComplete() {

Log.d(TAG, “onComplete() called”);

}

});

我们看一下map函数的源码:

public final Observable map(Function<? super T, ? extends R> mapper) {

//判空略过

ObjectHelper.requireNonNull(mapper, “mapper is null”);

//RxJavaPlugins.onAssembly()是hook 上文提到过

return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));

}

RxJavaPlugins.onAssembly()是hook 上文提到过,所以我们只要看ObservableMap,它就是返回到我们手里的Observable:

public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {

//将function变换函数类保存起来

final Function<? super T, ? extends U> function;

public ObservableMap(ObservableSource source, Function<? super T, ? extends U> function) {

//super()将上游的Observable保存起来 ,用于subscribeActual()中用。

super(source);

this.function = function;

}

@Override

public void subscribeActual(Observer<? super U> t) {

source.subscribe(new MapObserver<T, U>(t, function));

}

它继承自AbstractObservableWithUpstream,该类继承自Observable,很简单,就是将上游的ObservableSource保存起来,做一次wrapper,所以它也算是装饰者模式的提现,如下:

abstract class AbstractObservableWithUpstream<T, U> extends Observable implements HasUpstreamObservableSource {

//将上游的ObservableSource保存起来

protected final ObservableSource source;

AbstractObservableWithUpstream(ObservableSource source) {

this.source = source;

}

@Override

public final ObservableSource source() {

return source;

}

}

关于ObservableSource,代表了一个标准的无背压的 源数据接口,可以被Observer消费(订阅),如下:

public interface ObservableSource {

void subscribe(Observer<? super T> observer);

}

所有的Observable都已经实现了它,所以我们可以认为ObservableObservableSource在本文中是相等的

public abstract class Observable implements ObservableSource {

所以我们得到的ObservableMap对象也很简单,就是将上游的Observable和变换函数类Function保存起来

Function的定义超级简单,就是一个接口,给我一个T,还你一个R.

public interface Function<T, R> {

R apply(T t) throws Exception;

}

本例写的是将String->int.

重头戏subscribeActual()是订阅真正发生的地方,ObservableMap如下编写,就一句话,用MapObserver订阅上游Observable。

@Override

public void subscribeActual(Observer<? super U> t) {

//用MapObserver订阅上游Observable。

source.subscribe(new MapObserver<T, U>(t, function));

}

MapObserver也是装饰者模式,对终点(下游)Observer修饰。

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保存起来

super(actual);

//保存Function变量

this.mapper = mapper;

}

@Override

public void onNext(T t) {

//done在onError 和 onComplete以后才会是true,默认这里是false,所以跳过

if (done) {

return;

}

//默认sourceMode是0,所以跳过

if (sourceMode != NONE) {

actual.onNext(null);

return;

}

//下游Observer接受的值

U v;

//这一步执行变换,将上游传过来的T,利用Function转换成下游需要的U。

try {

v = ObjectHelper.requireNonNull(mapper.apply(t), “The mapper function returned a null value.”);

} catch (Throwable ex) {

fail(ex);

return;

}

//变换后传递给下游Observer

actual.onNext(v);

}

到此我们梳理一下流程:

订阅的过程,是从下游到上游依次订阅的。

  1. 终点 Observer 订阅了 map 返回的ObservableMap

  2. 然后mapObservable(ObservableMap)在被订阅时,会订阅其内部保存上游Observable,用于订阅上游的Observer是一个装饰者(MapObserver),内部保存了下游(本例是终点)Observer以便上游发送数据过来时,能传递给下游

  3. 以此类推,直到源头Observable被订阅,根据上节课内容,它开始向Observer发送数据

数据传递的过程,当然是从上游push到下游的,

  1. 源头Observable传递数据给下游Observer(本例就是MapObserver

  2. 然后MapObserver接收到数据,对其变换操作后(实际的function在这一步执行),再调用内部保存的下游ObserveronNext()发送数据给下游

  3. 以此类推,直到终点Observer

线程调度subscribeOn


简化问题,代码如下:

Observable.create(new ObservableOnSubscribe() {

@Override

public void subscribe(ObservableEmitter e) throws Exception {

Log.d(TAG, “subscribe() called with: e = [” + e + “]” + Thread.currentThread());

e.onNext(“1”);

e.onComplete();

}

//只是在Observable和Observer之间增加了一句线程调度代码

}).subscribeOn(Schedulers.io())

.subscribe(new Observer() {

@Override

public void onSubscribe(Disposable d) {

Log.d(TAG, “onSubscribe() called with: d = [” + d + “]”);

}

@Override

public void onNext(String value) {

Log.d(TAG, “onNext() called with: value = [” + value + “]”);

}

@Override

public void onError(Throwable e) {

Log.d(TAG, “onError() called with: e = [” + e + “]”);

}

@Override

public void onComplete() {

Log.d(TAG, “onComplete() called”);

}

});

只是在ObservableObserver之间增加了一句线程调度代码:.subscribeOn(Schedulers.io()).

查看subscribeOn()源码:

public final Observable subscribeOn(Scheduler scheduler) {

//判空略过

ObjectHelper.requireNonNull(scheduler, “scheduler is null”);

//抛开Hook,重点还是ObservableSubscribeOn

return RxJavaPlugins.onAssembly(new ObservableSubscribeOn(this, scheduler));

}

等等,怎么有种似曾相识的感觉,大家可以把文章向上翻,看看map()的源码。

subscribeOn()的套路如出一辙,那么我们根据上面的结论,

先猜测**ObservableSubscribeOn类也是一个包装类(装饰者)**,点进去查看:

public final class ObservableSubscribeOn extends AbstractObservableWithUpstream<T, T> {

//保存线程调度器

final Scheduler scheduler;

public ObservableSubscribeOn(ObservableSource source, Scheduler scheduler) {

//map的源码中我们分析过,super()只是简单的保存ObservableSource

super(source);

this.scheduler = scheduler;

}

@Override

public void subscribeActual(final Observer<? super T> s) {

//1 创建一个包装Observer

final SubscribeOnObserver parent = new SubscribeOnObserver(s);

//2 手动调用 下游(终点)Observer.onSubscribe()方法,所以onSubscribe()方法执行在 订阅处所在的线程

s.onSubscribe(parent);

//3 setDisposable()是为了将子线程的操作加入Disposable管理中

parent.setDisposable(scheduler.scheduleDirect(new Runnable() {

@Override

public void run() {

//4 此时已经运行在相应的Scheduler 的线程中

source.subscribe(parent);

}

}));

}

和map套路大体一致,ObservableSubscribeOn自身同样是个包装类,同样继承AbstractObservableWithUpstream

创建了一个SubscribeOnObserver类,该类按照套路,应该也是实现了ObserverDisposable接口的包装类,让我们看一下:

static final class SubscribeOnObserver extends AtomicReference implements Observer, Disposable {

//真正的下游(终点)观察者

final Observer<? super T> actual;

//用于保存上游的Disposable,以便在自身dispose时,连同上游一起dispose

final AtomicReference s;

SubscribeOnObserver(Observer<? super T> actual) {

this.actual = actual;

this.s = new AtomicReference();

}

@Override

public void onSubscribe(Disposable s) {

//onSubscribe()方法由上游调用,传入Disposable。在本类中赋值给this.s,加入管理。

DisposableHelper.setOnce(this.s, s);

}

//直接调用下游观察者的对应方法

@Override

public void onNext(T t) {

actual.onNext(t);

}

@Override

public void onError(Throwable t) {

actual.onError(t);

}

@Override

public void onComplete() {

actual.onComplete();

}

//取消订阅时,连同上游Disposable一起取消

@Override

public void dispose() {

DisposableHelper.dispose(s);

DisposableHelper.dispose(this);

}

@Override

public boolean isDisposed() {

return DisposableHelper.isDisposed(get());

}

//这个方法在subscribeActual()中被手动调用,为了将Schedulers返回的Worker加入管理

void setDisposable(Disposable d) {

DisposableHelper.setOnce(this, d);

}

}

这两个类根据上一节的铺垫加上注释,其他都好理解,稍微不好理解的应该是下面两句代码:

//ObservableSubscribeOn类

//3 setDisposable()是为了将子线程的操作加入Disposable管理中

parent.setDisposable(scheduler.scheduleDirect(new Runnable() {

@Override

public void run() {

//4 此时已经运行在相应的Scheduler 的线程中

source.subscribe(parent);

}

}));

//SubscribeOnObserver类

//这个方法在subscribeActual()中被手动调用,为了将Schedulers返回的Worker加入管理

void setDisposable(Disposable d) {

DisposableHelper.setOnce(this, d);

}

其中scheduler.scheduleDirect(new Runnable()..)方法源码如下:

/**

  • Schedules the given task on this scheduler non-delayed execution.

*/

public Disposable scheduleDirect(Runnable run) {

return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);

}

从注释和方法名我们可以看出,这个传入的Runnable会立刻执行

再继续往里面看:

public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {

//class Worker implements Disposable ,Worker本身是实现了Disposable

final Worker w = createWorker();

//hook略过

final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);

//开始在Worker的线程执行任务,

w.schedule(new Runnable() {

@Override

public void run() {

try {

//调用的是 run()不是 start()方法执行的线程的方法。

decoratedRun.run();

} finally {

//执行完毕会 dispose()

w.dispose();

}

}

}, delay, unit);

//返回Worker对象

return w;

}

createWorker()是一个抽象方法,由具体的Scheduler类实现,例如IoScheduler对应的Schedulers.io().

public abstract Worker createWorker();

初看源码,为了了解大致流程,不宜过入深入,先点到为止。

OK,现在我们总结一下scheduler.scheduleDirect(new Runnable()..)的重点:

  1. 传入的Runnable立刻执行的。

  2. 返回的**Worker对象就是一个Disposable对象**,

  3. Runnable执行时,是直接手动调用的 run(),而不是 start()方法.

  4. 上一点应该是为了,能控制在run()结束后(包括异常终止),都会自动执行Worker.dispose().

而返回的**Worker对象**也会被parent.setDisposable(...)加入管理中,以便在手动dispose()时能取消线程里的工作。

我们总结一下subscribeOn(Schedulers.xxx())过程

  1. 返回一个ObservableSubscribeOn包装类对象

  2. 上一步返回的对象被订阅时,回调该类中的subscribeActual()方法,在其中会立刻将线程切换到对应的Schedulers.xxx()线程。

  3. 在切换后的线程中,执行source.subscribe(parent);对上游(终点)Observable订阅

  4. 上游(终点)Observable开始发送数据,根据RxJava2 源码解析(一),上游发送数据仅仅是调用下游观察者对应的onXXX()方法而已,所以此时操作是在切换后的线程中进行


一点扩展,

大家可能看过一个结论:

subscribeOn(Schedulers.xxx())切换线程N次,总是以第一次为准,或者说离源Observable最近的那次为准,并且对其上面的代码生效(这一点对比的ObserveOn())。

为什么?

- 因为根据RxJava2 源码解析(一)中提到,订阅流程从下游往上游传递

- 在subscribeActual()里开启了Scheduler的工作,source.subscribe(parent);,从这一句开始切换了线程,所以在这之上的代码都是在切换后的线程里的了。

- 但如果连续切换最上面的切换最晚执行,此时线程变成了最上面的subscribeOn(xxxx)指定的线程,

- 而数据push时,是从上游到下游的,所以会在离源头最近的那次subscribeOn(xxxx)的线程里push数据(onXXX())给下游。

可写如下代码验证:

Observable.create(new ObservableOnSubscribe() {

@Override

public void subscribe(ObservableEmitter e) throws Exception {

Log.d(TAG, “subscribe() called with: e = [” + e + “]” + Thread.currentThread());

e.onNext(“1”);

e.onComplete();

}

}).subscribeOn(Schedulers.io())

.map(new Function<String, String>() {

@Override

public String apply(String s) throws Exception {

//依然是io线程

Log.d(TAG, “apply() called with: s = [” + s + “]” + Thread.currentThread());

return s;

}

})

.subscribeOn(Schedulers.computation())

.subscribe(new Observer() {

@Override

public void onSubscribe(Disposable d) {

Log.d(TAG, “onSubscribe() called with: d = [” + d + “]”);

}

@Override

public void onNext(String value) {

Log.d(TAG, “onNext() called with: value = [” + value + “]”);

}

@Override

public void onError(Throwable e) {

Log.d(TAG, “onError() called with: e = [” + e + “]”);

}

@Override

public void onComplete() {

Log.d(TAG, “onComplete() called”);

}

});

线程调度observeOn


在上一节的基础上,增加一个observeOn(AndroidSchedulers.mainThread()),就完成了观察者线程的切换。

.subscribeOn(Schedulers.computation())

//在上一节的基础上,增加一个ObserveOn

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new Observer() {

继续看源码吧,我已经能猜出来了,hook+new XXXObservable();

一线互联网大厂Java核心面试题库

image

正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

d onError(Throwable e) {

Log.d(TAG, “onError() called with: e = [” + e + “]”);

}

@Override

public void onComplete() {

Log.d(TAG, “onComplete() called”);

}

});

线程调度observeOn


在上一节的基础上,增加一个observeOn(AndroidSchedulers.mainThread()),就完成了观察者线程的切换。

.subscribeOn(Schedulers.computation())

//在上一节的基础上,增加一个ObserveOn

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new Observer() {

继续看源码吧,我已经能猜出来了,hook+new XXXObservable();

一线互联网大厂Java核心面试题库

[外链图片转存中…(img-tdaazmN6-1714869463854)]

正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值