Spring5的函数式编程使用了ProjectReactor工程的类,使用最为多的就是Mono和Flux类型,其中Mono是针对0到1个元素进行操作,Flux是针对多个元素进行操作。要使用这两个类前提是自己要有jdk8,Lambda,函数式编程的基础,否则请先学习了以上知识再来接触Spring5的Mono和FLux。
我们针对Mono类的一行代码,来进行源码分析与讲解。代码如下:
Mono.just("hello").subscribe(System.out::println);
这行代码是生成有一个元素的Mono类,并打印“hello”字符串。
首先,通过Mono.just()方法生成了Mono类
public static <T> Mono<T> just(T data) {
return onAssembly(new MonoJust<>(data));
}
以上代码可以看到是创建了一个MonoJust类型,这个类和Mono,FLux类型一样在reactor-core包中,其实Mono的每个方法都会对应生成一个Mono的子类,其子类很多,如下:
截图只是列举了一部分,Mono采用这种每个方法都生成一个类的方式是与jdk8中的Stream流水线的最大区别,目的是为了重用任意阶段的结果,且其所有子类都实现了Mono类的方法:
public abstract void subscribe(CoreSubscriber<? super T> actual);
这个方法我们后面会讲,它的作用就是处理后面的函数式的逻辑。
在返回MonoJust类型后,我们调用了subscribe(System.out::println)方法,这个方法在Mono类有具体实现,方法如下:
public final Disposable subscribe(Consumer<? super T> consumer) {
Objects.requireNonNull(consumer, "consumer");
return subscribe(consumer, null, null);
}
这个方法是所有Mono的子类执行subscribe(CoreSubscriber<? super T> actual)方法的入口,我们进入看下,执行到了如下方法:
public final Disposable subscribe(
@Nullable Consumer<? super T> consumer,
@Nullable Consumer<? super Throwable> errorConsumer,
@Nullable Runnable completeConsumer,
@Nullable Consumer<? super Subscription> subscriptionConsumer) {
return subscribeWith(new LambdaMonoSubscriber<>(consumer, errorConsumer,
completeConsumer, subscriptionConsumer));
}
我们看到有四个参数,根据字面意思即可理解,lambda表达式是第一个参数consumer,可以看到执行Lambda的方法时候创建了一个类型LambdaMonoSubscriber,这个类型封装了封装了四个参数。
后面进入此方法:
@Override
public final void subscribe(Subscriber<? super T> actual) {
onLastAssembly(this).subscribe(Operators.toCoreSubscriber(actual));
}
这个方法是重写了父类Publisher的suscribe方法,我们看到代码做了类型转换,通过类型转换就转换为了可以调用MonoJust中的subscribe方法了,MonoJust总的subscribe方法如下,所有的Mono子类都重写了此方法:
@Override
public void subscribe(CoreSubscriber<? super T> actual) {
actual.onSubscribe(Operators.scalarSubscription(actual, value));
}
然后通过LambdaMonoSubscriber的onSubscribe方法在调用Operators的request方法,再调用此LambdaMonoSubscriber的onNext方法,最后调用了我们自己写的Lambda表达式,如下:
@Override
public final void onNext(T x) {
Subscription s = S.getAndSet(this, Operators.cancelledSubscription());
if (s == Operators.cancelledSubscription()) {
Operators.onNextDropped(x, Context.empty());
return;
}
if (consumer != null) {
try {
consumer.accept(x);
}
consumer就是我们传入进来的Lambda表达式,这个方法继承自Suscriber类
通过这种方式,Publisher发送的subscribe就被Subscriber类消费掉了。其实全程都是一个单线程的操作。借鉴了消费订阅模式。
关于Mono的方法很多,在此只是举了一个简单的例子,其他的方法也可以通过类似的方式去研究。
在此处有一篇比较好的介绍Reactor编程的文章