Files
rikako-note/spring/webflux/spring webflux.md
2025-03-10 12:56:28 +08:00

8.5 KiB
Raw Blame History

Spring Webflux

Concept

核心机制

reactive

reactive代表基于“事件响应”的编程模型

back pressure

在spring webflux中back pressure为反应式编程的核心机制,用于协调生产者和消费者之间的速率差异,令系统在高负载或资源受限的情况下仍能稳定运行。

  • 同步场景在同步场景下阻塞式调用是一种天然的back pressure形式调用方会阻塞并等待直到被调用方执行完成
  • 非阻塞场景:在非阻塞的代码中,需要关注事件速率,生产者产生事件的速率不能压过消费者消费的速率
reactive stream

reactive stream为一个小型规范定义了异步组件和back pressure交互的规范。reactive stream的主要用途是让Subscriber控制publisher产生数据的速率。

编程模型

spring-web module包含Spring webflux的响应式基础包括若夏内容

  • http抽象
  • 对支持server的reactive stream adapters
  • codecs
  • 核心WebHandler API其与servlet api兼容

Spring webflux提供了如下两种编程模型

  • Annotated Controllers: 和spring mvc一致基于相同的注解。spring mvcwebflux controllers都支持reactive return type,因此,很难区分spring mvcwebflux controllers
  • Functional Endpoint基于lambda的、轻量的函数编程模型。其可以被看做是一个支持对请求进行route和handle的工具集合。

并发模型

spring mvc

spring mvc通常为servlet应用其假设当前线程可能会被阻塞例如远程调用等会阻塞当前线程。为了减少处理请求时阻塞所带来的影响servlet容器会使用包含大量线程的线程池。

webflux

对于webflux通常为non-blocking server其会假设应用并不会阻塞故而非阻塞的server可以使用一个线程数较少且固定的线程池event loop workers来处理请求。

调用阻塞api

当想要在webflux中使用阻塞api时可以按如下方式进行使用。RxJavaReactive都支持publushOn操作,其支持在另一个线程中继续执行

Reactive Core

spring-web对于reactive web应用具有如下支持

  • 对于server request的处理拥有如下两种级别的支持
    • HttpHandler 基于non-blocking I/OReactive Stream back pressure,适配`Reactor Netty, Undertow, Tomcat, Jetty以及任一Servlet Container
    • WebHandler稍高级别的、通用的web api用于请求处理在此基础上构建基于annotated controllersfunctional endpoints的编程模型
  • 对于client端ClientHttpConnector用于发送http请求同时兼容非阻塞io和Reactive Stream back pressure
  • codecs用于客户端和服务端的序列化和反序列化

HttpHandler

HttpHandler中只通过一个单独的方法来处理请求和相应其对不同的http server api进行了最小化的抽象。

下表描述了支持的api

Server name Server API used Reactive Streams support

Netty

Netty API

Reactor Netty

Undertow

Undertow API

spring-web: Undertow to Reactive Streams bridge

Tomcat

Servlet non-blocking I/O; Tomcat API to read and write ByteBuffers vs byte[]

spring-web: Servlet non-blocking I/O to Reactive Streams bridge

Jetty

Servlet non-blocking I/O; Jetty API to write ByteBuffers vs byte[]

spring-web: Servlet non-blocking I/O to Reactive Streams bridge

Servlet container

Servlet non-blocking I/O

spring-web: Servlet non-blocking I/O to Reactive Streams bridge

下表中描述了server依赖

Server name Group id Artifact name

Reactor Netty

io.projectreactor.netty

reactor-netty

Undertow

io.undertow

undertow-core

Tomcat

org.apache.tomcat.embed

tomcat-embed-core

Jetty

org.eclipse.jetty

jetty-server, jetty-servlet

server api adapters

如下示例展示了如何使用HttpHandler Adapters来适配不同的Server Api

Reactor Netty
HttpHandler handler = ...
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
HttpServer.create().host(host).port(port).handle(adapter).bindNow();
Undertow
HttpHandler handler = ...
UndertowHttpHandlerAdapter adapter = new UndertowHttpHandlerAdapter(handler);
Undertow server = Undertow.builder().addHttpListener(port, host).setHandler(adapter).build();
server.start();
Tomcat
HttpHandler handler = ...
Servlet servlet = new TomcatHttpHandlerAdapter(handler);

Tomcat server = new Tomcat();
File base = new File(System.getProperty("java.io.tmpdir"));
Context rootContext = server.addContext("", base.getAbsolutePath());
Tomcat.addServlet(rootContext, "main", servlet);
rootContext.addServletMappingDecoded("/", "main");
server.setHost(host);
server.setPort(port);
server.start();
Jetty
HttpHandler handler = ...
Servlet servlet = new JettyHttpHandlerAdapter(handler);

Server server = new Server();
ServletContextHandler contextHandler = new ServletContextHandler(server, "");
contextHandler.addServlet(new ServletHolder(servlet), "/");
contextHandler.start();

ServerConnector connector = new ServerConnector(server);
connector.setHost(host);
connector.setPort(port);
server.addConnector(connector);
server.start();

WebHandler API

org.springframework.web.server package基于HttpHandler构建提供了通用的Web API。Web Api由多个WebException, 多个WebFilter, 一个WebHandler组件构成组成了一个chain。