一、开篇
本文将解析 Spring 的 Reactor 项目的源码。主要目的是让自己能深入理解 Reactor 这个项目,以及 Spring 5 和 Spring Boot 2。
Project Reactor 项目地址:https://github.com/reactor
Reactor 项目主要包含 Reactor Core 和 Reactor Netty 两部分。Reactor Core 实现了反应式编程的核心功能,Reactor Netty 则是 Spring WebFlux 等技术的基础。本文将介绍 Core 模块的核心原理。
本文从一个例子开始:
1 2 3 4 5 6 | public static void main(String[] args) { Flux.just("tom", "jack", "allen") .filter(s -> s.length() > 3) .map(s -> s.concat("@qq.com")) .subscribe(System.out::println); } |
整个 Project Reactor 的核心调用分为下面几个阶段:
- 声明阶段
- subscribe 阶段
- onSubscribe 阶段
- request 阶段
- 调用阶段
接下来对每个阶段详细介绍。
二、声明阶段
简介
之前的文章介绍过,反应式编程和传统风格的编程一个最大的不同点在于,开发人员编写的大部分代码都是在声明处理过程。即这些代码并不会被实际的执行,直到开始被订阅。这便是为何第一阶段是声明阶段的原因。
详解
先来看第一个方法
1 2 3 4 5 6 7 8 | public static <T> Flux<T> just(T... data) { return fromArray(data); } public static <T> Flux<T> fromArray(T[] array) { // 省略不重要的部分 return onAssembly(new FluxArray<>(array)); } |
just 方法只是创建反应式流的众多方式的一个。在实际工作中,更常见的通过反应式 Repository 将数据库查询结果,或通过 Spring 5 的WebClient 将 HTTP 调用结果最为流的开始。
接下来
再接下来
看一下源码
1 2 3 4 5 6 7 8 9 10 11 12 13 | public final Flux<T> filter(Predicate<? super T> p) { if (this instanceof Fuseable) { return onAssembly(new FluxFilterFuseable<>(this, p)); } return onAssembly(new FluxFilter<>(this, p)); } FluxFilterFuseable(Flux<? extends T> source, Predicate<? super T> predicate) { super(source); this.predicate = Objects.requireNonNull(predicate, "predicate"); } |
这里有个逻辑判断,就是返回的值分为了
而接下来的
三、subscribe 阶段
简介
subscribe 阶段同行会触发数据发送。在本例中,后面可以看到,对于
详解
当调用
1 2 3 4 5 | public void subscribe(CoreSubscriber<? super R> actual) { source.subscribe( new MapFuseableSubscriber<>(actual, mapper) ); } |
其中的
这里强调一下
Publisher 接口中的subscribe 方法语义上有些奇特,它表示的不是订阅关系,而是被订阅关系。即aPublisher.subscribe(aSubscriber) 表示的是aPublisher 被aSubscriber 订阅。
接下来调用的就是
1 2 3 4 5 | public void subscribe(CoreSubscriber<? super T> actual) { source.subscribe( new FilterFuseableSubscriber<>(actual, predicate) ); } |
这时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public static <T> void subscribe(CoreSubscriber<? super T> s, T[] array) { if (array.length == 0) { Operators.complete(s); return; } if (s instanceof ConditionalSubscriber) { s.onSubscribe( new ArrayConditionalSubscription<>( (ConditionalSubscriber<? super T>) s, array ) ); } else { s.onSubscribe(new ArraySubscription<>(s, array)); } } |
最重要的部分还是
可以这样简单理解,对于中间过程的
四、onSubscribe 阶段
简介
在调用
详解
s 是
1 2 3 4 5 6 | public void onSubscribe(Subscription s) { if (Operators.validate(this.s, s)) { this.s = (QueueSubscription<T>) s; actual.onSubscribe(this); } } |
actual 对应
调用过程:
五、request 阶段
含义
onSubscribe 阶段是表示订阅动作的方式,让各
详解
下面是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public final void onSubscribe(Subscription s) { if (Operators.validate(subscription, s)) { this.subscription = s; if (subscriptionConsumer != null) { try { subscriptionConsumer.accept(s); } catch (Throwable t) { Exceptions.throwIfFatal(t); s.cancel(); onError(t); } } else { s.request(Long.MAX_VALUE); } } } |
由上可见
这里需要说明,如
下面是
1 2 3 | public void request(long n) { s.request(n); } |
最后
与 map、filter 等操作不同,flatMap 有比较大的差异,感兴趣的同学可以自己研究一下。本文先不详细介绍。
六、调用阶段
含义解释
这一阶段将会通过调用
流程分解
在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public void request(long n) { if (Operators.validate(n)) { if (Operators.addCap(REQUESTED, this, n) == 0) { if (n == Long.MAX_VALUE) { fastPath(); } else { slowPath(n); } } } } void fastPath() { final T[] a = array; final int len = a.length; final Subscriber<? super T> s = actual; for (int i = index; i != len; i++) { if (cancelled) { return; } T t = a[i]; if (t == null) { s.onError(new NullPointerException("The " + i + "th array element was null") ); return; } s.onNext(t); } if (cancelled) { return; } s.onComplete(); } |
于是接下来由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public void onNext(T t) { boolean b; try { b = predicate.test(t); } catch (Throwable e) { Throwable e_ = Operators.onNextError(t, e, this.ctx, s); if (e_ != null) { onError(e_); } else { s.request(1); } Operators.onDiscard(t, this.ctx); return; } if (b) { actual.onNext(t); } else { s.request(1); Operators.onDiscard(t, this.ctx); } } |
其最要部分是通过
下一个要处理的是
最终要处理数据的是
1 2 3 4 5 6 7 8 9 10 11 12 | public final void onNext(T x) { try { if (consumer != null) { consumer.accept(x); } } catch (Throwable t) { Exceptions.throwIfFatal(t); this.subscription.cancel(); onError(t); } } |
整个流程的解释到这里基本结束。
七、总结
接下来我们用一个图来回顾一下整体的流程。

Reactor Core
参考
需要感谢下面这篇文章,帮助我很好理解了 Project Reactor 的核心处理流程。
由表及里学 ProjectReactor:http://blog.yannxia.top/2018/06/26/java/spring/projectreactor/
作者:编走编想
链接:https://www.jianshu.com/p/df395eb28f69
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。