Spring WebFlux 手册(译文1.1 Overview(概要))

Spring WebFlux是Spring Framework 5.0引入的非阻塞式Web框架,支持Reactive Streams规范,适用于高并发场景。响应式编程模型以事件驱动,强调非阻塞I/O和反压控制,减少线程资源消耗。Reactor是Spring WebFlux的reactive编程库,提供Mono和Flux两种API。Spring WebFlux提供注解和函数式两种编程模型,适用于微服务和轻量级函数式编程。服务端支持包括Tomcat、Jetty、Servlet容器和Netty等,性能优势在于使用少量线程和内存进行伸缩。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.Spring WebFlux

1.1. Overview(概要)

1.1.1. Define “Reactive” (如何定义响应式编程)

1.1.2. Reactive API

1.1.3. Programming Models,编程模型

1.1.4. Applicability(技术选型)

1.1.5. Servers(服务端支持)

1.1.6. Performance

1.1.7.  Concurrency Model

 

1.Spring WebFlux

Spring Framework 在一开始,只是建立在Servlet API 和 Servlet 容器基础上的Web 框架。Spring WebFlux 是在5.0版本后才开发出来的,它是一个 I/O 非阻塞式,支持 Reactive Streams (https://www.reactive-streams.org/) 规范的Web 框架。

以上两种框架可以任选一个,也可以并存使用。比如 在使用Spring MVC 的同时,使用 reactive WebClient。但是服务端只能选其中一个。

1.1. Overview(概要)

为什么开发Spring WebFlux

部分原因是我们需要使用较少的线程和硬件资源来处理高并发非阻塞I/O请求。在Servlet 3.1  已经提供了非阻塞 I/O API,但是现在我们暂时先不考虑Servlet API。这就是我们开发新的non-blocking运行时API的动机。更重要的原因是一些服务框架 比如Netty 已经完美实现了异步和non-blocking服务开发方式。

另外的原因是函数编程。除了在Java5 提供的注解编程外,Java 8 提供lambda 函数编程API。这是实现 异步非阻塞编程的另外一个福音了。Java8 使得Spring WebFlux 可以在语言级别提供函数编程模型。

1.1.1. Define “Reactive” (如何定义响应式编程)

我们提到 非阻塞和 函数编程 ,那么什么是Reactive?

Reactive是基于事件响应的编程模型,事件包括 网络I/O事件、页面的鼠标点击事件等等。也就是说非阻塞编程就是Reactive,因为相对阻塞式编程而言,非阻塞编程以响应事件的通知为主,这些事件通知包括系统操作的状态变化和数据的状态变化。

Spring reactive研发组考虑到一个非常重要的机制,那就是在non-blocking情况下的限流控制(又称 反压)问题。在同步调用情况下,一个很平常的限流控制(又称 反压)方式就是让调用者等待。但是在non-blocking情况下,去控制响应事件的速率就变得非常重要,我们要防止响应事件的速率超过限定值。

Reactive Streams 是一个比较小的规范,它定义了 异步编程和限流控制(又称 反压)之间交互设计的方式,这个标准已经纳入到 Java9 的规范中了。比如一个Publisher 可以生成一条消息给Subscriber(HTTP server),Subscriber收到消息并处理反馈给Publisher。Reactive Streams重要设计目标就是让Subscriber 去控制 Publisher 发送消息的速率。

这里有一个有趣的问题:如果说publisher不能降低发送消息速率应该怎么办?

Reactive Streams仅仅是确立编制机制和功能边界。如果说publisher不能降低发送速率,那就让它 buffer缓存,丢弃消息 甚至失败。

1.1.2. Reactive API

Reactive Streams在交互设计中扮演着一个非常重要的角色。但是由于它太底层了,对于编写应用层API没有太大作用。编写一个应用需要更高级的,功能更丰富,且具有函数编程特性的API。就像java8 Stream API 一样,但是不能仅限于集合。这就是Reactive 编程库要扮演的角色。

Reactorhttps://github.com/reactor/reactor)就是 Spring WebFlux的reactive编程库。它提供了 MonoFlux 两种类型的API。Mono使用 0..1个序列,Flux使用0..N个序列。ReactiveX 提供了非常丰富的操作API 来处理 Mono 和Flux (reactivex.io/documentation/operators.html)。Reactor是响应式编程库,他所有的API都是非阻塞式的,并更专注于java服务端开发。它是与Spring紧密合作开发的

WebFlux 以Reactor作为核心代码库,同时又可以与其他符合Reactive Streams规范的代码库结合使用。作为一个基本的原则,WebFlux API 可以接受普通的Publisher作为输入,内部与Reactor编程模型做适配,最返回Flux或者 Mono作为输出。所以,你可以使用任意Publisher作为输入,同时通过API处理输出,但是你必须将输出适配到其他的响应式编程库。只要可行(例如,带注释的控制器)WebFlux就可以透明地适配到RxJava或其他反应性库的使用。具体详情可以见 Reactive Libraries 。第五章。

1.1.3. Programming Models,编程模型

在Spring WebFlux基础上,spring-web同样包含事件响应的功能组件,

包括HTTP的抽象实现,服务端适配Reactive Streams规范的组件,编码规范,以及与Servlet API类似的具有非阻塞式编程特点的核心WebHandler API

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

Annotated Controllers: 声明式编程模型即Spring WebFlux同样支持类似Spring MVC的注解定义Controllers。Spring MVCWebFlux控制器 也都都支持反应式(ReactorRxJava)返回类型,在这一点上,很难将它们区分开来。其中一个显著的区别是WebFlux还支持注解@RequestBody来处理事件响应参数。

Functional Endpoints:另一个是基于lambda的轻量级函数式编程模型。你可将函数式编程看做是一个小的代码库,或者是可以路由和处理请求的一组应用套件。这与基于注解的编程最大的区别是应用程序从头到尾负责请求处理,而不通过注解来声明调用方法。

1.1.4. Applicability(技术选型)

使用Spring MVC 还是WebFlux?

这是个很平常的问题,但却还是有歧义的。事实上,两者可以相互辅助来解决更大范围的问题。两个框架的设计是具有连续性和一致性的,你可以同时使用两个框架的功能,每个框架来处理自己擅长的问题,这对双方都是有益的。下图展示了两者之间的关系,并列出了两者共同点和差异。

在使用的过程中,我们建议考虑以下几点:

  1. 如果你已经有了一个运行良好的Spring MVC应用,那就没有必要去更换。命令式编程是编写、理解和调试代码的最简单方法。因为从历史上看,大多数代码库都是阻塞的,你可以选择更多的库,结合到现有的框架中。
  2. 如果你已经有一个非阻塞的web 技术栈,那么你可以考虑使用Spring WebFlux作为替代方案,它可以提供同样的功能,同时Spring WebFlux 提供了多种服务端容器支持(Netty, Tomcat, Jetty, Undertow, 和 Servlet 3.1+ containers),注解和函数式编程,以及与其他Reactor代码库的集成(Reactor, RxJava等等)
  3. 如果你对java8 或者Kotlin提供的轻量级函数式编程比较感兴趣,你可以考虑使用Spring WebFlux 。也可以使用Spring WebFlux作为web服务的站点,对于要求不那么复杂的小型应用程序或微服务来说,这也是一个不错的选择,这样可以得到更大的透明度和更好的控制。
  4. 在微服务体系结构中,我们可以把Spring MVCSpring WebFlux控制器或Spring WebFlux函数式端点组合到一个应用程序中。这两个框架都支持基于注释的编程模型,这使得重用代码变得更容易,同时也为正确的工作选择了正确的工具。
  5. 评估应用程序技术上扩展性的一个简单方法是检查它的依赖那些组件,如果您要使用阻塞性api (JPAJDBC)或网络api,那么Spring MVC至少是系统架构上的最佳选择。从技术上讲,同时在单独的线程上使用Reactor RxJava 是可行的,但是你无法最大的利用非阻塞技术栈的优点。
  6. 如果你已经有了一个Spring MVC应用程序,同时又需要远程调用其他的服务,这时可以尝试事件响应式客户端WebClient通过WebClient ,可以直接从Spring MVC控制器方法返回响应式返回结果(Reactor, RxJava或其他),并且每次远程调用的延迟或调用之间的相互依赖性越大,得到的好处就越大。Spring MVC控制器也可以通过WebClient调用其他支持事件响应的功能组件。
  7. 如果你已经有了一个大型研发团队,还要用Spring WebFlux技术栈,就必须要权衡陡峭的学习曲线和收益了。一个切实可行的方式就是使用Spring WebFlux部分技术栈 比如WebClient,除此外,可以从小的地方着手使用Spring WebFlux。我们认为对于绝大部分的应用程序,转变到基于事件响应式编程是不必要的。如果你还不确定使用响应式编程有哪些好处,可以首先了解下非阻塞I/O是如何工作的,以及其效果(例如,单线程Node.js上的并发性)

1.1.5. Servers(服务端支持)

Spring WebFlux支持在TomcatJettyServlet 3.1+ 等容器中运行,也支持像NettyUndertow那样独立运行。所有的容器都是支持底层公共的API的,这样更高层应用程序可以在多种容器中运行。

Spring WebFlux 并没有提供内嵌的停止或者启动的服务的功能组件。但是我们很容易通过几行代码利用Spring配置和WebFlux提供的基础功能组件来运行一个服务。

Spring Boot也有WebFlux starter组件来自动实现这些步骤,默认使用Netty,但也很容易通过修改Maven 或者Gradle依赖 来切换到Tomcat, Jetty 或者Undertow。Spring Boot默认为Netty,是因为它更广泛地用于异步和非阻塞编程,同时并允许客户端和服务器共享接入层代码。

Spring MVC 和WebFlux都可以使用Tomcat 和 Jetty,但是它们的使用方式是不一样的。Spring MVC基于Servlet API的阻塞式I/O编程。Spring WebFlux直接依赖于Servlet 3.1非阻塞式API,它也可以使用Servlet API但是底层要做适配,而不是直接使用。

对于Undertow 容器而言,Spring WebFlux可以在Undertow API基础上直接运行而不需要Servlet API的支持。

1.1.6. Performance

性能意味着很多东西,它的概念范围非常广。基于响应的非阻塞编程并不意味着应用程序一定会运行得更快,在某些情况下,他们是高性能的,例如,使用WebClient并行执行远程调用。总的来说,以非阻塞的方式实现应用需要更多的工作,并且有可能会稍微增加请求的处理时间。

响应式非阻塞编程的预期好处是能够使用少量固定数量的线程和更少的内存进行伸缩。这使得应用程序在高负载下以更可预测的方式进行伸缩。你需要在有一些延迟的情况下来观察它的好处,(包括慢速和不可预测的网络I/O混合)这时响应式非阻塞编程会开始显示其优势,依照不通的情况,其最终结果的差异可能是巨大的。

1.1.7.  Concurrency Model

Spring MVCSpring WebFlux都支持带注释的控制器,但是在并发模型和阻塞线程的假定设置上,有一个关键的区别。Spring MVC(一般的servlet应用程序)中,会假定应用程序可以阻塞当前线程(例如,用于远程调用),因此servlet容器会使用一个大的线程池来应对请求处理过程中可能出现的阻塞问题。但在Spring WebFlux(在一般的非阻塞服务器)中,会假定应用程序不会阻塞,因此,非阻塞服务器使用一个小的、固定大小的线程池(event loop workers)来处理请求。

提示:“可扩展”和“少量线程”听起来可能相互矛盾,但是由于不会阻塞当前线程(而是依赖回调)意味着你不需要额外的线程来预防阻塞的情况出现。

Invoking a Blocking API(阻塞式API)

如果确实需要使用阻塞线程,应该怎么办? ReactorRxJava都提供publishOn操作函数来控制线程的执行。这意味着在这种编程模型上开了一个口子。但是要记住,阻塞api并不适合这种并发模型。

Mutable State(可变状态)

ReactorRxJava中,你通过操作符声明逻辑,并且在运行时提供一个响应式管道,数据在管道中可以在不同的阶段按都顺序进行处理。这样做的一个好处是,它使应用程序不必关心数据状态的变化,因为管道中的应用程序代码永远不会被其他应用程序并发调用。

 

Threading Model(线程模型)

What threads should you expect to see on a server running with Spring WebFlux?

  • 普通的”Spring WebFlux服务器上(例如,没有数据访问,也没有其他可选的依赖项),你可以设置一个线程用于服务器端接收请求,设置几个线程用于处理请求,通常处理请求的线程数与CPU内核的数量一样多。但是,Servlet容器可以设置更多的线程(例如,Tomcat上的10个线程),以支持阻塞式I/Oservlet和非阻塞式I/OServlet 3.1

  • 响应式的WebClient采用event-loop方式。因此,你可以看到与之相关的少量固定数量的处理线程(例如, Netty连接器中的reactor-http-nio)但是,如果Netty同时用于客户端和服务端,则默认情况下它们共享event loop资源池。

  • ReactorRxJava都提供抽象线程池,称为调度器,可用于与publishOn操作符一起使用,后者用于将处理切换到不同的线程池。调度器都有一种特定的并发策略——例如,并行”(针对有限线程数量的cpu密集型程序)弹性伸缩”(针对大量线程的I/ o密集型程序)如果您看到这样的线程,这意味着某些代码正在使用特定的线程池调度器策略。

  • 允许数据访问库和其他第三方依赖包也可以创建和使用它们自己的线程。

 

Configuring(如何配置)

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值