Spring WebFlux(译)

2021-04-23  本文已影响0人  简楼

前言

今天在做幂等性校验由Spring WebMvc 转 Spring webFlux,发现网上关于 Spring webFlux 中文资料比较少,所以自己手动有道翻译一份,仅做自己学习使用,做个记录,感谢!

关于 Spring WebFlux 的翻译时基于版本 Version 5.3.6 的;

原文地址

1.Spring WebFlux

Spring框架中包含的原始web框架,Spring web MVC,是专门为Servlet API和Servlet容器而构建的。响应式堆栈web框架Spring WebFlux是在5.0版本中添加的。它是完全无阻塞的,支持响应流回压,并运行在Netty、Undertow和Servlet 3.1+容器等服务器上

这两个web框架都反映了它们的源模块的名称(Spring -webmvc和Spring -webflux),并在Spring框架中共存。每个模块都是可选的。应用程序可以使用一个或另一个模块,或者在某些情况下同时使用两个模块——例如,带有响应性WebClient的Spring MVC控制器。

1.1. Overview (概述)

为什么要创建Spring WebFlux ?

部分原因是需要一个非阻塞的web堆栈来处理少量线程的并发性,并使用更少的硬件资源进行扩展。Servlet 3.1确实为非阻塞I/O提供了一个API。然而,使用它会远离Servlet API的其他部分,其中契约是同步的(Filter, Servlet)或阻塞的(getParameter, getPart)。这是一个新的通用API作为任何非阻塞运行时的基础的动机。这很重要,因为服务器(如Netty)是在异步、非阻塞空间中建立的。

答案的另一部分是函数式编程。就像Java 5中添加注释创造了机会(比如带注释的REST控制器或单元测试)一样,Java 8中添加lambda表达式也为Java中的功能性api创造了机会。这对于允许声明式组合异步逻辑的非阻塞应用程序和延续风格的api(由CompletableFuture和ReactiveX普及)来说是一个福音。在编程模型级别,Java 8使Spring WebFlux能够提供功能性的web端点和带注释的控制器。

1.1.1. Define “Reactive” (响应式的定义)

我们谈到了“非阻塞”和“功能性”,但是响应式是什么意思呢?

术语“响应式”指的是围绕对变化作出反应而构建的编程模型——网络组件对I/O事件作出反应,UI控制器对鼠标事件作出反应,等等。从这个意义上说,非阻塞是响应式的,因为我们现在处于操作完成或数据可用时响应通知的模式,而不是被阻塞;

还有另一个重要的机制,我们在Spring团队中与“响应式”联系在一起,那就是无阻塞的背压。在同步的命令式代码中,阻塞调用是迫使调用者等待的一种自然形式的背压。在非阻塞代码中,控制事件的速率使快速的生产者不会淹没其目标变得很重要。

响应流是一个小规范(也在Java 9中采用),它定义了带有背压的异步组件之间的交互。例如,数据存储库(充当发布服务器)可以生成HTTP服务器(充当订阅服务器)随后可以写入响应的数据。响应流的主要目的是让订阅者控制发布者产生数据的速度。

思考:如果生产者不能放慢速度怎么办?
响应式流的目的只是建立机制和边界。如果生产者不能放慢速度,它就必须决定是缓冲、删除还是失败。

1.1.2. Reactive API(响应式API)

响应式流在互操作性中扮演着重要的角色。它对库和基础设施组件很感兴趣,但作为应用程序API用处不大,因为它太低级了。应用程序需要一个更高级、更丰富的功能性API来组成异步逻辑——类似于Java 8 Stream API,但不只是用于集合。这就是响应式库所扮演的角色。

Reactor是Spring WebFlux的响应式库的选择。它提供Mono和Flux API类型来处理0..1的数据序列(Mono)和0 . .N (Flux)到一组与操作符的ReactiveX词汇表对齐的丰富操作符。Reactor是一个Reactive Streams库,因此,它的所有操作人员都支持无阻塞的背压。Reactor非常关注服务器端Java。它是与Spring紧密协作开发的。

WebFlux需要Reactor作为一个核心依赖,但是它可以通过 reactive Streams 与其他的 reactive 库互操作。作为一个通用规则,WebFlux API 接受一个普通的 Publisher 作为输入,在内部将其调整为一个 Reactor 类型,使用它,并返回一个Flux或Mono作为输出。因此,您可以传递任何 Publisher 作为输入,并可以对输出应用操作,但您需要调整输出以便与另一个响应式库一起使用。只要可行(例如,带注释的控制器),WebFlux就会透明地适应RxJava或其他响应性库的使用。有关更多细节,请参阅响应式库。

除了响应式api之外,WebFlux还可以与Kotlin中的协程api一起使用,后者提供了一种更命定的编程风格。下面的Kotlin代码示例将与协程api一起提供。

1.1.3. Programming Models(编程模型)

Spring -web模块包含了Spring WebFlux的响应式基础,包括HTTP抽象、响应式流适配器,支持的服务器、编解码器和一个核心的WebHandler API,类似于Servlet API,但没有阻塞协议。

在此基础上,Spring WebFlux提供了两种编程模型的选择:

1.1.4. Applicability(使用范围)

Spring MVC 还是 WebFlux?

这是一个很自然的问题,但却建立了一个不合理的二分法。实际上,两者共同努力扩大了可用选择的范围。这两种设计都是为了彼此的连续性和一致性,它们可以并排使用,并且来自每一方的反馈对双方都有利。下图显示了两者之间的关系,它们有什么共同之处,以及它们各自支持的独特之处:

image.png

我们建议您考虑以下几点:

1.1.5. Servers(服务)

Spring WebFlux支持Tomcat, Jetty, Servlet 3.1+容器,以及Netty和Undertow等非Servlet运行时。所有服务器都适应于低级的公共API,这样就可以跨服务器支持高级编程模型。

Spring WebFlux没有启动或停止服务器的内置支持。然而,很容易从Spring配置和WebFlux基础设施组装一个应用程序,并使用几行代码运行它。

Spring Boot有一个WebFlux启动器,可以自动执行这些步骤。默认情况下,初学者使用Netty,但是通过改变Maven或Gradle的依赖关系,很容易切换到Tomcat、Jetty或Undertow。Spring Boot默认为Netty,因为它更广泛地用于异步、非阻塞空间,并允许客户端和服务器共享资源。

Tomcat和Jetty可以与Spring MVC和WebFlux一起使用。但是请记住,它们的使用方式是非常不同的。Spring MVC依赖于Servlet阻塞I/O,并允许应用程序在需要时直接使用Servlet API。Spring WebFlux依赖于Servlet 3.1非阻塞I/O,并使用底层适配器背后的Servlet API。不能直接使用。

对于Undertow, Spring WebFlux直接使用Undertow API,而不使用Servlet API。

1.1.6. Performance(性能)

性能具有许多特征和意义。响应式和非阻塞通常不会使应用程序运行得更快。在某些情况下,它们可以(例如,如果使用WebClient并行运行远程调用)。总的来说,非阻塞方式需要更多的工作,这可能会略微增加所需的处理时间。

响应式和非阻塞的主要预期好处是能够使用少量固定数量的线程和更少的内存进行扩展。这使得应用程序在负载下更有弹性,因为它们可以以更可预测的方式伸缩。然而,为了观察这些好处,您需要有一些延迟(包括缓慢和不可预测的网络I/O)。这就是反应性堆栈开始显示其优势的地方,差异可能是戏剧性的。

1.1.7. Concurrency Model(并发模型)

Spring MVC和Spring WebFlux都支持带注释的控制器,但是在并发模型和阻塞和线程的默认设置上有一个关键的区别。

在Spring MVC(以及一般的servlet应用程序)中,设定应用程序可以阻塞当前线程(例如,对于远程调用)。因此,servlet容器使用大型线程池来吸收请求处理期间可能出现的阻塞。

在Spring WebFlux(以及一般的非阻塞服务器)中,设定应用程序不会阻塞。因此,非阻塞服务器使用一个小的、固定大小的线程池(事件循环工作者)来处理请求。

“扩展”和“少量线程”听起来可能矛盾,但永远不阻塞当前线程(而依赖回调)意味着你不需要额外的线程,因为没有阻塞调用需要吸收。

调用阻塞API

如果您确实需要使用一个阻塞库怎么办?Reactor和RxJava都提供了publishOn操作符,以在不同的线程上继续处理。这意味着有个容易的安全出口。但是,请记住,阻塞api并不适合这种并发模型。

可变状态

在Reactor和RxJava中,通过操作符声明逻辑。在运行时,会形成一个响应式管道,其中数据会在不同的阶段顺序处理。这样做的一个关键好处是,它使应用程序不必保护可变状态,因为该管道中的应用程序代码永远不会并发调用。

线程模型

您希望在使用Spring WebFlux运行的服务器上看到哪些线程?

配置

Spring框架不支持启动和停止服务器。要为服务器配置线程模型,您需要使用特定于服务器的配置api,或者,如果您使用Spring Boot,请检查每个服务器的Spring Boot配置选项。您可以直接配置WebClient。对于所有其他库,请参阅它们各自的文档。

上一篇 下一篇

猜你喜欢

热点阅读