Spring WebFlux核心組件詳解
環(huán)境:Springboot2.4.12
概述
spring-web模塊包含了對響應式web應用程序的以下基本支持:
- 對于服務器請求處理,有兩個級別的支持。
- HttpHandler:處理HTTP請求的基本協(xié)議,包括非阻塞I/O和響應式流背壓,以及Reactor Netty、Undertow、Tomcat、Jetty和任何Servlet 3.1+容器的適配器。
- WebHandler API:稍微高級一點的,用于處理請求的通用web API,在此基礎上構建具體的編程模型,如帶注釋的控制器和函數(shù)式端點。
- 對于客戶端,有一個基本的ClientHttpConnector契約來執(zhí)行HTTP請求,包括非阻塞I/O和響應式流回壓,以及Reactor Netty, Reactive Jetty HttpClient和Apache HttpComponents的適配器。應用程序中使用的高級web客戶端構建在這個基本契約之上。
- 對于客戶端和服務器,用于HTTP請求和響應內容的序列化和反序列化的編解碼器。
HttpHandler
HttpHandler是一個簡單的協(xié)議,只有一個方法來處理請求和響應。它故意最小化,其主要和唯一的目的是在不同的HTTP服務器api上提供最小的抽象。
支持的服務器api如下表所示:
服務器 | 服務的API | 反應式流支持 |
Netty | Netty API | Reactor Netty |
Undertow | Undertow API | spring-web: Undertow到Reactive Streams橋接 |
Tomcat | Servlet 3.1 non-blocking I/O; Tomcat API to read and write ByteBuffers vs byte[] | spring-web:Servlet 3.1非阻塞 I/O到Reactive Streams橋接 |
Jetty | Servlet 3.1 non-blocking I/O; Jetty API to write ByteBuffers vs byte[] | spring-web:Servlet 3.1非阻塞 I/O到Reactive Streams橋接 |
Servlet 3.1 container | Servlet 3.1 non-blocking I/O | spring-web: Servlet 3.1非阻塞 I/O到Reactive Streams橋接 |
下表描述了服務器依賴關系:
服務器 | 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 |
下面的代碼片段顯示了在每個服務器API中使用HttpHandler適配器:
- Reactor Netty
- Undertow
- Tomcat
- Jetty
- Servlet 3.1+ Container
要將war部署到任何Servlet 3.1+容器,你可以擴展并在war中包含
AbstractReactiveWebInitializer。這個類用ServletHttpHandlerAdapter封裝了一個HttpHandler,并將其注冊為Servlet。
部分源碼:?
WebHandler
org.springframework.web.server包構建在HttpHandler契約之上,為通過多個WebExceptionHandler、多個WebFilter和單個WebHandler組件的鏈處理請求提供通用的web API。只需指向自動檢測組件的Spring ApplicationContext,或者向構建器注冊組件,就可以將該鏈與WebHttpHandlerBuilder組合在一起。
HttpHandler的目標很簡單,就是抽象出不同的HTTP服務器,而WebHandler API的目標是提供web應用中常用的更廣泛的功能,例如:
- 具有屬性的用戶會話
- 請求屬性
- 已解析請求的區(qū)域設置或主體
- 訪問已解析和緩存的表單數(shù)據(jù)
- 多部分數(shù)據(jù)的摘要。
- 等等
特殊bean類型
下表列出了WebHttpHandlerBuilder可以在Spring ApplicationContext中自動檢測或直接注冊的組件:
Bean name | Bean type | Count | Description |
<any> | WebExceptionHandler | 0..N | 為來自WebFilter實例鏈和目標WebHandler的異常提供處理。 |
<any> | WebFilter | 0..N | 在過濾器鏈的其余部分和目標WebHandler的前后應用攔截樣式邏輯。 |
webHandler | WebHandler | 1 | 請求處理程序。 |
webSessionManager | WebSessionManager | 0..1 | 通過ServerWebExchange上的方法公開的WebSession實例管理器。默認為DefaultWebSessionManager。 |
serverCodecConfigurer | ServerCodecConfigurer | 0..1 | 用于訪問HttpMessageReader實例,解析表單數(shù)據(jù)和multipart數(shù)據(jù),然后通過ServerWebExchange上的方法公開這些數(shù)據(jù)。默認情況下是servercodecconfiguration.create()。 |
localeContextResolver | LocaleContextResolver | 0..1 | LocaleContext的解析器通過ServerWebExchange上的方法公開。默認為AcceptHeaderLocaleContextResolver。 |
forwardedHeaderTransformer | ForwardedHeaderTransformer | 0..1 | 對于處理轉發(fā)的類型頭,可以提取并刪除它們,也可以只刪除它們。默認不使用。 |
Form Data
ServerWebExchange公開了以下訪問表單數(shù)據(jù)的方法:
DefaultServerWebExchange使用配置的HttpMessageReader將表單數(shù)據(jù)(
application/x-www-form-urlencoded)解析為MultiValueMap。默認情況下,F(xiàn)ormHttpMessageReader被配置為由ServerCodecConfigurer bean使用。
Multipart Data
ServerWebExchange公開了以下訪問多部分數(shù)據(jù)的方法:
DefaultServerWebExchange使用配置的HttpMessageReader<MultiValueMap<String, Part>>來將multipart/form-data內容解析為MultiValueMap。默認情況下,這是DefaultPartHttpMessageReader,它沒有任何第三方依賴。另外,還可以使用基于Synchronoss nio Multipart庫的SynchronossPartHttpMessageReader。兩者都是通過ServerCodecConfigurer bean進行配置的。
要以流式方式解析多部分數(shù)據(jù),你可以使用HttpMessageReader<Part>返回的` Flux<Part> `。例如,在帶注釋的控制器中,使用@RequestPart意味著通過名稱訪問各個部分,就像map一樣,因此需要完整解析多個部分的數(shù)據(jù)。相比之下,可以使用@RequestBody將內容解碼到Flux<Part>,而無需收集到MultiValueMap。
Filters
在WebHandler API中,你可以使用WebFilter在過濾器和目標WebHandler處理鏈的其余部分之前和之后應用攔截風格的邏輯。當使用WebFlux配置時,注冊WebFilter就像把它聲明為Spring bean一樣簡單,并且(可選地)通過在bean聲明上使用@Order或實現(xiàn)Ordered來表示優(yōu)先級。
Exceptions
在WebHandler API中,可以使用WebExceptionHandler來處理來自WebFilter實例鏈和目標WebHandler的異常。當使用WebFlux配置時,注冊WebExceptionHandler就像聲明它為Spring bean一樣簡單,并且(可選)通過在bean聲明上使用@Order或實現(xiàn)Ordered來表示優(yōu)先級。
下表描述了可用的WebExceptionHandler實現(xiàn):
Exception Handler | Description |
ResponseStatusExceptionHandler | 通過將響應設置為異常的HTTP狀態(tài)碼,提供對ResponseStatusException類型異常的處理。 |
WebFluxResponseStatusExceptionHandler | 擴展了ResponseStatusExceptionHandler,它還可以確定任何異常的@ResponseStatus注解的HTTP狀態(tài)碼。 這個處理程序是在WebFlux配置中聲明的。 |
Codecs
spring-web和spring-core模塊通過非阻塞I/O提供響應式流回壓,支持序列化和反序列化與高層對象之間的字節(jié)內容。下面介紹這種支持:
- Encoder與Decoder是底層協(xié)議,獨立于HTTP對內容進行編碼和解碼。
- HttpMessageReader和HttpMessageWriter是編碼和解碼HTTP消息內容的協(xié)議。
- Encoder可以使用EncoderHttpMessageWriter包裝,以適應在web應用程序中使用,而 Decoder可以使用DecoderHttpMessageReader包裝。
- DataBuffer抽象了不同的字節(jié)緩沖區(qū)表示形式(例如Netty ByteBuf、java.nio。ByteBuffer等),也是所有編解碼器都能處理的。
spring-core模塊提供了byte[]、ByteBuffer、DataBuffer、Resource和String編碼器和解碼器的實現(xiàn)。spring-web模塊提供了Jackson JSON、Jackson Smile、JAXB2、Protocol buffer和其他Encoder和Decoder,以及針對表單數(shù)據(jù)、多部分內容、服務器發(fā)送事件等只支持web的HTTP消息閱讀器和writer實現(xiàn)。