对于最新稳定版本,请使用Spring Framework 7.0.1spring-doc.cadn.net.cn

概述

春季网络流为何诞生?spring-doc.cadn.net.cn

部分原因是需要一个非阻塞的网络栈来处理并发少量线程,并以更少的硬件资源实现扩展。Servlet 非阻塞 I/O使其远离 Servlet API 的其他部分,后者合同是同步的 (Filter,servlet)或阻挡(getParameter,getPart). 这就是推动建立一个新的通用 API 作为跨越任何非阻塞运行时的基础。 那是 重要原因是有服务器(如Netty)在异步空间中已稳固建立,非阻塞空间。spring-doc.cadn.net.cn

答案的另一部分是函数式编程。就像注释的添加一样Java 5 创造了机会(如带注释的 REST 控制器或单元测试),Java 8 中lambda 表达式的加入为 Java 功能性 API 创造了机会。这对非阻塞应用和延续式 API(如其普及)是一大福音 由完成未来以及ReactiveX)支持声明式异步逻辑的组合。在编程模型层面,Java 8使SpringWebFlux能够提供功能齐全的Web端点以及带注释的控制器。spring-doc.cadn.net.cn

定义“被动型”吗?

我们提到了“非阻塞”和“功能性”,但反应性到底是什么意思?spring-doc.cadn.net.cn

“响应式”一词指的是围绕响应变化构建的编程模型——网络组件响应I/O事件,UI控制器响应鼠标事件等。从这个意义上说,非阻塞是被动的,因为我们不再被阻挡,而是处于当作完成或数据可用时响应通知的模式。spring-doc.cadn.net.cn

我们还有一个重要机制,我们Spring团队将“反应性”联系在一起那就是非阻塞性反压。在同步、命令式代码中,阻断呼叫作为一种自然的背压形式,迫使呼叫者等待。在非阻塞性代码中,控制事件速率变得非常重要,这样快速的生产者不会压倒其目的地。spring-doc.cadn.net.cn

响应式流是一个小型规范(也被Java 9采纳)它定义了异步组件之间带有反压的交互。例如,一个数据存储库(作为发布者)可以产生HTTP服务器(作为订阅者)能够写入响应的数据。然后可以写入响应。响应式流的主要目的是让订阅者控制发布者生成数据的速度或速度。spring-doc.cadn.net.cn

常见问题:如果发布者无法放慢速度怎么办?
响应式流的目的仅是建立机制和界限。如果发布者无法放慢速度,就必须决定是缓冲、丢弃还是失败。

响应式API

响应式流在互作性方面起着重要作用。它对图书馆具有重要意义 以及基础设施组件,但作为应用API的实用性较低,因为它太过于 低级。应用程序需要更高级、更丰富、功能更丰富的 API 来实现 comp async 逻辑——类似于 Java 8API 但不仅仅是集合。 这正是响应式库所扮演的角色。spring-doc.cadn.net.cn

反应是 的首选响应式库 春季网络流。它提供了通量API 类型 用于处理0..1的数据序列()和0..N(通量)通过一组丰富的算子,与 ReactiveX 运算符词汇。 反应器是一个反应流库,因此其所有操作员都支持非阻断背压。 Reactor 非常专注于服务器端 Java。该项目在密切合作下开发 和Spring一起。spring-doc.cadn.net.cn

WebFlux 需要 Reactor 作为核心依赖,但它可以与其他响应式设备互作 通过反应流(Reactive Streams)获取图书馆。一般来说,WebFlux API 接受发行人作为输入,将其内部调整为反应堆类型,使用该类型,返回通量或者作为输出。所以,你可以通过任何发行人作为输入,你可以应用 但你需要将输出调整以配合另一个响应式库。 在可行的情况下(例如,带注释的控制器),WebFlux 会透明地适应这种使用情况 RxJava 或其他响应式库。详情请参见响应式库spring-doc.cadn.net.cn

除了响应式 API,WebFlux 还可以与 Kotlin 中的协程 API 一起使用,这提供了更具命令式的编程风格。 以下 Kotlin 代码示例将与协程 API 一同提供。

编程模型

春网模块包含了Spring WebFlux的响应式基础, 包括HTTP抽象、响应式流适配器 服务器、编解码器和核心WebHandler应用程序接口可与 Servlet API 但采用了非阻塞的契约。spring-doc.cadn.net.cn

基于此,Spring WebFlux 提供了两种编程模式的选择:spring-doc.cadn.net.cn

  • 注释控制器:与Spring MVC一致,基于相同的注释 来自春网模块。Spring MVC 和 WebFlux 控制器都支持响应式 (Reactor 和 RxJava) 返回类型,因此很难区分它们。其中一个值得一提的 区别在于 WebFlux 也支持响应式@RequestBody参数。spring-doc.cadn.net.cn

  • 函数端点:基于Lambda的、轻量级的函数式编程模型。你可以考虑 这作为一个小型库或一组工具,应用程序可以用来路由和 处理请求。注释控制器最大的区别在于应用 负责从头到尾处理请求,而非通过声明意向 注释和被回电。spring-doc.cadn.net.cn

适用性

春季MVC还是WebFlux?spring-doc.cadn.net.cn

这是一个自然而然的问题,但却造成了一个不合理的二分法。其实,两者都有 共同努力,扩大可选方案的范围。这两者设计为 它们之间的连续性和一致性是并存的,并且可以获得反馈 双方都受益。下图展示了两者的关系及其关系 有共同点,以及各自独特的支持点:spring-doc.cadn.net.cn

春季MVC和Webflux Venn

我们建议您考虑以下具体要点:spring-doc.cadn.net.cn

  • 如果你的 Spring MVC 应用运行良好,就没必要更改。 命令式编程是编写、理解和调试代码最简单的方法。 你可以最大限度地选择库,因为历史上大多数库都是封锁的。spring-doc.cadn.net.cn

  • 如果你已经在寻找非阻塞的网页栈,Spring WebFlux 也提供类似的服务 执行模型与该领域的其他模型相比更有利,同时也提供了服务器选择 (Netty、Tomcat、Jetty、Undertow 和 Servlet 容器),编程模型的选择 (注释控制器和功能性网页端点),以及响应式库的选择 (Reactor、RxJava 或其他)spring-doc.cadn.net.cn

  • 如果你对一个轻量级、功能丰富的Web框架感兴趣,用于Java 8 lambda或者Kotlin,你可以使用Spring WebFlux的功能性网页端点。这也是一个不错的选择对于较小的应用或需求较少的微服务,这些需求更为复杂,可以受益于更高的透明度和控制力。spring-doc.cadn.net.cn

  • 在微服务架构中,你可以混合使用Spring MVC或Spring WebFlux控制器,或Spring WebFlux功能端点。支持在两个框架中支持相同的基于注释的编程模型,使得在选择合适的工具的同时,重新利用知识,以完成正确的工作。spring-doc.cadn.net.cn

  • 评估应用的一个简单方法是检查其依赖关系。如果你有阻断持久化API(JPA、JDBC)或网络API可用,Spring MVC是最佳选择至少对于常见架构来说是这样。技术上,在Reactor和RxJava上都可以在独立线程上执行阻断调用,但你不会充分利用一个非阻断的网络栈。spring-doc.cadn.net.cn

  • 如果你有带有远程服务调用的 Spring MVC 应用,可以试试被动式Web客户端. 你可以返回反应类型(Reactor、RxJava 或其他)直接来自 Spring MVC 控制器方法。每次调用的延迟越大,或者调用之间的相互依赖性越大,收益就越显著。Spring MVC 控制器也可以调用其他响应式组件。spring-doc.cadn.net.cn

  • 如果你的团队很大,请记住转向非阻塞编程时的陡峭学习曲线,函数式和声明式编程。一个实用的开始方式是不完全切换是使用响应式编程Web客户端. 除此之外,从小做起,衡量收益。我们预计,对于各种应用来说,这种转变是不必要的。如果你不确定该寻找哪些好处,首先了解非阻塞I/O的工作原理(例如,单线程Node.js上的并发)及其影响。spring-doc.cadn.net.cn

服务器

Spring WebFlux 支持于 Tomcat、Jetty、Servlet 容器,以及非 Servlet 运行时如 Netty 和 Undertow。所有服务器都适配到低级别的通用 API,以便支持更高级的编程模型跨服务器。spring-doc.cadn.net.cn

Spring WebFlux 没有内置启动或停止服务器的支持。然而,从 Spring 配置和 WebFlux 基础设施组装应用程序并运行起来非常简单只需几行代码。spring-doc.cadn.net.cn

Spring Boot 有一个 WebFlux 启动程序,可以自动化这些步骤。默认情况下,启动程序使用Netty,但通过更改你的Maven 或 Gradle 依赖,切换到 Tomcat、Jetty 或 Undertow 也很容易。Spring Boot 默认使用 Netty,因为它更广泛用于异步、非阻塞空间,允许客户端和服务器共享资源。spring-doc.cadn.net.cn

Tomcat 和 Jetty 可以同时使用 Spring MVC 和 WebFlux。但请记住它们的使用方式非常不同。Spring MVC 依赖于 Servlet 阻断输入输出,并且让应用程序在需要时直接使用 Servlet API。Spring WebFlux依赖于 Servlet 非阻塞 I/O,并在低层次使用 Servlet API 适配器。 它不会直接暴露在外。spring-doc.cadn.net.cn

强烈建议不要在WebFlux应用的上下文中映射Servlet过滤器或直接作Servlet API。基于上述原因,在同一上下文中混合阻塞I/O和非阻塞I/O会导致运行时问题。

对于 Undertow,Spring WebFlux 直接使用 Undertow API,而非 Servlet API。spring-doc.cadn.net.cn

性能

性能具有许多特性和含义。响应式和非阻塞性通常不会让应用程序运行更快。在某些情况下,它们可以——例如,如果使用Web客户端并行运行远程通话。不过,这需要更多的工作 用非阻塞的方式处理,这会稍微增加处理时间。spring-doc.cadn.net.cn

响应式和非阻塞性的关键预期优势是能够以小规模的 线程数量固定,内存更少。这使应用程序在负载下更具韧性, 因为它们的规模更可预测。然而,为了享受这些好处,你必须 需要有一定的延迟(包括缓慢且不可预测的网络I/O混合)。 这正是响应式堆栈开始展现其优势的地方,差异可以 戏剧性的。spring-doc.cadn.net.cn

并发模型

Spring MVC 和 Spring WebFlux 都支持带注释的控制器,但有一个密钥 并发模型与阻塞和线程默认假设的差异。spring-doc.cadn.net.cn

在 Spring MVC(以及一般的 servlet 应用)中,假设应用程序可以 阻断当前线程,(例如,用于远程调用)。因此,servlet 容器 使用大型线程池来吸收请求处理过程中潜在的阻塞。spring-doc.cadn.net.cn

在 Spring WebFlux(以及一般非阻塞服务器)中,假设应用程序 不要拉黑。因此,非阻塞服务器使用一个小型、固定大小的线程池 (事件循环工作人员)处理请求。spring-doc.cadn.net.cn

“按比例”和“线数少”听起来可能矛盾,但永远不要阻挡 当前线程(并且依赖回调)意味着你不需要额外的线程,因为 没有阻挡电话需要承受。

调用阻塞 API

如果你确实需要用分区库怎么办?Reactor 和 RxJava 都提供了发布作符继续在另一个线程上处理。这意味着有 轻松逃生。不过请记住,阻断API并不适合 这是并发模型。spring-doc.cadn.net.cn

可变状态

在 Reactor 和 RxJava 中,你通过运算符声明逻辑。运行时,是响应式的 流水线形成时,数据按顺序、不同阶段进行处理。一个关键的好处 其中之一是它使应用程序无需保护可变状态,因为 该流水线中的应用程序代码绝不会同时调用。spring-doc.cadn.net.cn

线程模型

运行 Spring WebFlux 的服务器上应该预期会看到哪些线程?spring-doc.cadn.net.cn

  • 在“原版”Spring WebFlux服务器上(例如,没有数据访问或其他可选功能 依赖关系),你可以预期服务器端有一个线程,请求线程则有好几个线程 处理(通常与CPU核心数相当)。然而,servlet 容器, 可能从更多线程开始(例如Tomcat上有10个线程),以支持Servlet(阻塞)I/O两种 以及servlet 3.1(非阻塞)I/O使用。spring-doc.cadn.net.cn

  • 响应式Web客户端采用事件循环方式运行。所以你可以看到一个小而固定的 与该数据相关的处理线程数量(例如,reactor-http-nio-与反应堆合作 Netty连接器)。然而,如果Reactor Netty同时用于客户端和服务器,则两者 默认共享事件循环资源。spring-doc.cadn.net.cn

  • Reactor 和 RxJava 提供了线程池抽象,称为调度器,用于发布用于切换处理到不同线程池的作符。 调度器名称暗示了特定的并发策略——例如,“并行” (针对线程数量有限的CPU工作)或“弹性”(用于I/O受限的工作,且 大量线程)。如果你看到这样的线程,说明某些代码正在使用 特定线程池调度策略。spring-doc.cadn.net.cn

  • 数据访问库和其他第三方依赖也可以创建和使用 thread 他们自己的。spring-doc.cadn.net.cn

配置

Spring 框架不支持服务器的启动和停止。为了配置服务器的线程模型, 你需要使用服务器特定的配置API,或者如果你使用Spring Boot, 检查每台服务器的Spring Boot配置选项。你可以配置Web客户端径直。 关于其他所有图书馆,请参见各自的文档。spring-doc.cadn.net.cn