webflux源码解析(2)-reactor

webflux框架是基于Project Reactor构建的,是一种响应式的编码方式,因此webflux的源码跟其它框架看起来差别较大。代码实际执行时也是异步的,哪怕通过debug断点跟进流程,也显得有些难懂。

为了看明白webflux的代码,本文梳理了reactor的基本接口设计、代码执行逻辑。

通过逐个方法的跟进,可以发现,所谓的响应式编程并不是魔法,对于具体的方法而言,还是一个线程同步、阻塞的去执行。所谓的响应式,需要相对应的客户端配合,这个待后续文章讨论。

1. 接口概述

分析之前,先看一下reactor提供的顶级接口

在这里插入图片描述
发布者
Publisher 是一个可以发送无限序列元素的发布者,允许调用多次,每次调用都会启动一个新的Subscription。每个Subscription只能被一个Subscriber使用;Subscriber消费者只能订阅一次Publisher。

//发布者
public interface Publisher<T> {
    /**
     * 订阅方法
     * 请求发布者启动数据流
     * @param s   消费者
     */
    public void subscribe(Subscriber<? super T> s);
}

订阅者(消费者)

其中Subscriber#onSubscribe只会被调用一次

public interface Subscriber<T> {
    /**
     * 该方法在调用Publisher#subscribe(Subscriber)后执行
     * 在Subscription#request(long)调用之前不会有数据流消费
     * 如果订阅者想要消费更多的数据,需要调用Subscription#request(long)来请求数据。
     */
    public void onSubscribe(Subscription s);
    /**
     * 消费下一个消息
     * 在调用Subscription#request(long)方法时,Publisher会通过这个方法来通知订阅者消息
     * @param t 数据元素
     */
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
}


Subscription

public interface Subscription {
    public void request(long n);
    public void cancel();
}
  • Subscription的生命周期是订阅者对发布者的一次消费
  • 一个Subscription只能被一个Subscriber使用
  • Subscription不仅允许请求数据,也允许取消对数据的请求,并且支持资源清理
  • 在通过org.reactivestreams.Subscription#request发送需求信号之前,不会有任何事件产生。该方法请求的数量最大是 Long.MAX_VALUE

Processor
一种即是发布者又是消费者的组件

public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}

2. 方法执行

2.1 subscribe方法说明

示例:

Flux.just(1, 2, 3, 4, 5)
	.subscribe(new CoreSubscriber<>() {//这里传入CoreSubscriber对象作为订阅者
		@Override
		public void onSubscribe(Subscription s) {
			log.info("onSubscribe, {}", s.getClass());
			s.request(5);
		}
		@Override
		public void onNext(Integer integer) {
			log.info("onNext: {}", integer);
		}
		@Override
		public void onError(Throwable t) {
		}
		@Override
		public void onComplete() {
			log.info("onComplete");
		}
	});

以下是调用的方法跟踪,调用 Flux.just 方法:

在这里插入图片描述
在这里插入图片描述

查看示例中的代码可知 subscribe() 方法调用的是 FluxArray#subscribe

在这里插入图片描述

通过 FluxArray#subscribe 方法调用到我们定义的 onSubscribe 方法,进而调用 FluxArray.ArraySubscription#request 方法
在这里插入图片描述

FluxArray.ArraySubscription#slowPath 方法中循环拉去数组中的元素,执行onNext方法,最后执行 onComplete 方法

在这里插入图片描述

[!NOTE] 总结

  • Publisher中定义了数据源
  • Subscriber 中定义了数据处理的动作
  • Subscription 中定义了数据处理的过程,编排了 Subscriber 中定义的方法

在这里插入图片描述

2.2 processor 方法说明

示例:

Flux.just(1, 2, 3, 4, 5)
	.map(i -> i * i)
	.subscribe(new CoreSubscriber<>() {
		//省略,与之前相同
	});

跟进执行的方法到 Flux#map 方法:
在这里插入图片描述

之后调用的 subscribe 方法是 FluxMapFuseable#subscribe

在这里插入图片描述

此时执行 FluxArray#subscribe 传入的不再是 FluxArray.ArraySubscription 对象,变成了 FluxMapFuseable.MapFuseableSubscriber 对象了,由于中间过程的组装,之后会进一步调用至 FluxMapFuseable.MapFuseableSubscriber#onSubscrib

在这里插入图片描述

此处调用 onSubscribe 方法时,传入的参数为this,即位为 MapFuseableSubscriber 对象,因此执行s.request(5) 时,s 是 MapFuseableSubscriber 对象,实际执行的方法是
FluxMapFuseable.MapFuseableSubscriber#request

在这里插入图片描述

最终还是委托 FluxArray.ArraySubscription#request 方法执行。由于这一层封装,导致执行 onNext 方法时,执行的是 FluxMapFuseable.MapFuseableSubscriber#onNext 方法,这里充当了消费者的角色

真的很绕
在这里插入图片描述

在这里插入图片描述

3. 其它示例说明

这是一个更通用的场景,通过异步任务定义Publisher

测试示例:

public void test(){  
    Mono.fromCallable(() -> {  
                // 执行阻塞操作,例如数据库查询  
                return "Some blocking operation result";  
            })  
            .subscribe(result -> {  
                System.out.println("Result: " + result);  
            });  
}

调用方法 Mono#fromCallable 时,返回的是 MonoCallable 对象
在这里插入图片描述

调用 subscribe() 方法时,调用的是 Mono#subscribe 方法,但会逐层封装(此处封装为LambdaMonoSubscriber

在这里插入图片描述

最终在此会调用到不同的实现,此处 this 即为 MonoCallable 对象

在这里插入图片描述

调用的subscribe最终为:MonoCallable#subscribe

在这里插入图片描述
actual 是 LambdaMonoSubscriber 对象,调用其 subscribe 方法

查看 LambdaMonoSubscriber#onSubscribe
在这里插入图片描述
继续跟进,调用MonoSubscriber#request
在这里插入图片描述
因此,此处actual.onSubscribe(sds)并没有实际意义

LambdaMonoSubscriber.complete 方法执行时,调用的是 LambdaMonoSubscriber 的onNext、onComplete方法,实际执行的就是示例中定义的
System.out.println("Result: " + result)
在这里插入图片描述

至此,全部方法执行完毕。

参考:

[1] reactor3 源码分析

  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值