Reactor顾名思义核反应堆,光听名字就知道它有多强了,首先Reactor是异步非阻塞的,基于netty,而tomcat不是,一个请求一个线程(除了Servlet3.1以上),使用Reactor就是整个代码在执行链上也更清晰,做过前端的同学应该很有感悟,不管是jquery还是vue都是一级一级往下点,那种感觉真的很爽,当然java8也有类似体验。所以诞生之初,这个东西就不是为了java而生的,java是重语言,强调稳定性,直到jdk1.8也不愿意为reactor妥协。最终Spring按奈不住了,率先把reactor集成至自己函数库中,所以Spring的版本至少是Spring5,而jdk至少是1.7,(因为Spring5实现了很多关于响应式编程的东西),然后webflux坑很深,完全看上去像另一门语言(重点),所以学习成本相对陡峭,我更多从使用者方向去思考。 国内使用这个技术的公司好像没几家,除了我上家公司以外(用的也不是很好),首先我知道的有阿里,当然也只是一部分技术部分,也是我同学告诉我的,然后我在这家公司刚做技术选型时注册中心还在纠结eureka还是nacos,因为我来这之前根本不会nacos,只是听过,用eureka倒是很熟,但是看到nacos支持响应式编程,我还是很开心的,加上其他一些因素还是选定了nacos。 所以大家暂时不用担心,这个技术暂时还不会取代java命令式编程,因为兼容其他中间件还需要时间,但是也是一个警告。
命令式编程一行一个代码,我们很明确就能知道,下一行代码跟上一行代码关系,因为是按步骤一步一步往下走的,最终返回的那个结果是上面一行一行代码组合最终的呈现结果。
而响应式编程不一样,它不会再描述每一步我们要进行的步骤,它只描述你要构建数据将要流经的管道,当数据流经管道时,可以对它们进行某种形式的修改或者使用。这样做的好处是我们不再关注每一行代码是做什么的(想象有100行代码),只需要关注管道最终返回的结果是什么,然后依据上一个管代的结果,流到我们这个管道需要做什么。每个管道都是异步非阻塞的。
主要原因是Servlet是阻塞和多线程的,每个连接都会使用一个线程。在请求处理的时候,会在线程池中拉取一个worker线程来对请求进行处理。同时,请求线程是阻塞的,直到worker线程提示它完成为止。这也带来的后果就是阻塞式Web框架在大量请求无法有效地扩展。缓慢的worker线程所带来的延迟会使情况变得更糟,因为它将花费更长的时间才能将worker线程送回池中,准备处理另一个请求。在某些场景中,这种设计完全可以接受。事实上,这种方式也是这十年来Web应用程序的开发方式,但是时代在改变。这种方式适合以前偶尔浏览网站的人们,而现在人们会频繁消费HTTPAPI,他们会持续地和Web API交换数据。
在Reactor中,经常使用的类并不多,主要有以下两个:
Mono 实现了 org.reactivestreams.Publisher 接口,代表0到1个元素的发布者(Publisher)Flux 同样实现了 org.reactivestreams.Publisher 接口,代表0到N个元素的发布者Mono和Flux都是Publisher,发布者起到发送流数据作用。
1.Subscriber,因为一次只请求一个元素会导致本身效率低下。 2.为了验证是不是一次请求一个元素,fromInter 或 range。 onComplete因为是多线程,为了防止发布者和订阅者结束后有个通知,否则会造成周期竞争。 onComplete或onError都会触发终止订阅
指在异步场景中,被观察者发送事件速度远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略,可能最终导致溢出。subscription
开发者应只关注Publisher ,如果开发中间件,redis、dubbo,甚至nacos, Web Flux 则会自动帮我们实现 Subscriber
Schedulers 类有如下几种对上下文操作的静态方法:
immediate():无执行上下文,提交的Runnable将直接在原线程上执行,可以理解没有调度single():可重用单线程,使用一个线程处理所有请求elastic(): 没有边界的弹性线程池boundedElastic():有边界弹性线程池,设置线程限制,默认为cpu核心数*10。达到上限后最多可以提交10万个任务。是阻塞线程的方法parallel(): 固定线程数量的并行线程池,线程数量和cpu内核一样多RouterFunction 类似 Spring Web 的 @RequestMapping 。RouterFunction 用来定义 Spring 5 应用的路由信息。RouterFunctions 助手类包含一些有用的方法,例如 route 定义路由并构建 RouterFunction 对象。RequestPredicates 包含大量有用的方法如 GET, POST, path, queryParam ,accept, headers, contentType 等等,可用来定义路由和构建 RouterFunction。每个 Route 映射到一个处理方法,当接收到 HttpRequest 请求的时候就会调用。
Mono 是在配置控制器方法中返回的,而不是controller。
RouterFunction 为应用程序提供了 DSL 风格的路由功能。此时,Spring 并不支持两种风格混合使用。