Files
rikako-note/spring/webflux/spring webflux.md
2025-03-10 20:50:50 +08:00

14 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。

相比于HttpHandler仅仅是对不同http server的抽象WebHandler提供了一个更加通用、更加广泛的功能集合:

  • user sessions attributes
  • request attributes
  • resolved Locale or Principal for request
  • abstractions for multipart data

bean types for WebHttpHandlerBuilder auto-detect

在spring上下文中WebHttpHandlerBuilder可以自动探测到如下类型的components:

Bean name Bean type Count Description

<any>

WebExceptionHandler

0..N

Provide handling for exceptions from the chain of WebFilter instances and the target WebHandler. For more details, see Exceptions.

<any>

WebFilter

0..N

Apply interception style logic to before and after the rest of the filter chain and the target WebHandler. For more details, see Filters.

webHandler

WebHandler

1

The handler for the request.

webSessionManager

WebSessionManager

0..1

The manager for WebSession instances exposed through a method on ServerWebExchange. DefaultWebSessionManager by default.

serverCodecConfigurer

ServerCodecConfigurer

0..1

For access to HttpMessageReader instances for parsing form data and multipart data that is then exposed through methods on ServerWebExchange. ServerCodecConfigurer.create() by default.

localeContextResolver

LocaleContextResolver

0..1

The resolver for LocaleContext exposed through a method on ServerWebExchange. AcceptHeaderLocaleContextResolver by default.

forwardedHeaderTransformer

ForwardedHeaderTransformer

0..1

For processing forwarded type headers, either by extracting and removing them or by removing them only. Not used by default.

Form Data

ServerWebExchange将会向外暴露如下方法用于访问form data

Mono<MultiValueMap<String, String>> getFormData();

DefaultServerWebExchange使用HttpMessageReader来对form dataapplication/x-www-form-urlencoded进行parse操作将formdata转化为MultiValueMap

Multipart Data

ServerWebExchange向外暴露如下方法用于访问multipart data。

Mono<MultiValueMap<String, Part>> getMultipartData();

DefaultServerWebExchange将会使用HttpMessageReader<MultiValueMap<String, Part>>来对multipart/form-datamultipart/mixedmultipart/related数据进行转换,数据将会被转化为MultiValueMap类型。

Filter

WebHandler API中,可以使用WebFilter来实现拦截式的逻辑,当使用Webflux Config时,WebFilter的注可以通过将其注册为bean来实现。

对于WebFilter的优先级,欸可以通过使用@Order注解或实现Ordered接口来实现。

CORS

spring webflux支持通过@CORSLAI1