WebFlux 配置
WebFlux Java 配置聲明瞭使用註解控制器或函式式端點處理請求所需的元件,並提供了自定義配置的 API。這意味著你無需理解 Java 配置建立的底層 bean。但是,如果你想了解它們,可以在 WebFluxConfigurationSupport 中檢視,或者在 特殊 Bean 型別 中閱讀更多關於它們的資訊。
對於配置 API 中沒有提供的更高階的定製,你可以透過 高階配置模式 完全控制配置。
啟用 WebFlux 配置
你可以在 Java 配置中使用 @EnableWebFlux 註解,示例如下
-
Java
-
Kotlin
@Configuration
@EnableWebFlux
public class WebConfig {
}
@Configuration
@EnableWebFlux
class WebConfig
使用 Spring Boot 時,你可能希望使用 WebFluxConfigurer 型別的 @Configuration 類,但不需要 @EnableWebFlux 來保留 Spring Boot WebFlux 的自定義。更多詳細資訊請參見 WebFlux 配置 API 部分 和 專門的 Spring Boot 文件。 |
上述示例註冊了多個 Spring WebFlux 基礎設施 bean,並適應了類路徑上可用的依賴項——用於 JSON、XML 等。
WebFlux 配置 API
在你的 Java 配置中,你可以實現 WebFluxConfigurer 介面,示例如下
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
// Implement configuration methods...
}
@Configuration
class WebConfig : WebFluxConfigurer {
// Implement configuration methods...
}
轉換、格式化
預設情況下,會安裝用於各種數字和日期型別的格式化程式,並支援透過在欄位和引數上使用 @NumberFormat、@DurationFormat 和 @DateTimeFormat 進行自定義。
要在 Java 配置中註冊自定義格式化程式和轉換器,請使用以下內容
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun addFormatters(registry: FormatterRegistry) {
// ...
}
}
預設情況下,Spring WebFlux 在解析和格式化日期值時會考慮請求的區域設定。這適用於日期以字串形式表示的表單(帶有“input”表單欄位)。然而,對於“date”和“time”表單欄位,瀏覽器使用 HTML 規範中定義的固定格式。對於此類情況,日期和時間格式化可以按如下方式進行自定義
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun addFormatters(registry: FormatterRegistry) {
val registrar = DateTimeFormatterRegistrar()
registrar.setUseIsoFormat(true)
registrar.registerFormatters(registry)
}
}
有關何時使用 FormatterRegistrar 實現的更多資訊,請參閱 FormatterRegistrar SPI 和 FormattingConversionServiceFactoryBean。 |
驗證
預設情況下,如果類路徑上存在 Bean Validation(例如,Hibernate Validator),LocalValidatorFactoryBean 將註冊為全域性 驗證器,用於 @Controller 方法引數上的 @Valid 和 @Validated。
在您的 Java 配置中,您可以自定義全域性 Validator 例項,示例如下
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public Validator getValidator() {
// ...
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun getValidator(): Validator {
// ...
}
}
請注意,您也可以區域性註冊 Validator 實現,示例如下
-
Java
-
Kotlin
@Controller
public class MyController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new FooValidator());
}
}
@Controller
class MyController {
@InitBinder
protected fun initBinder(binder: WebDataBinder) {
binder.addValidators(FooValidator())
}
}
如果您需要在某處注入 LocalValidatorFactoryBean,請建立一個 bean 並用 @Primary 標記它,以避免與 MVC 配置中宣告的 bean 發生衝突。 |
內容型別解析器
您可以配置 Spring WebFlux 如何從請求中確定 @Controller 例項的請求媒體型別。預設情況下,只檢查 Accept 頭,但您也可以啟用基於查詢引數的策略。
以下示例展示瞭如何自定義請求內容型別解析
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
// ...
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun configureContentTypeResolver(builder: RequestedContentTypeResolverBuilder) {
// ...
}
}
HTTP 訊息編解碼器
以下示例展示瞭如何自定義請求和響應體的讀取和寫入
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().maxInMemorySize(512 * 1024);
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
configurer.defaultCodecs().maxInMemorySize(512 * 1024)
}
}
ServerCodecConfigurer 提供了一組預設的讀取器和寫入器。您可以使用它來新增更多讀取器和寫入器、自定義預設的,或完全替換預設的。
對於 Jackson JSON 和 XML,考慮使用 Jackson2ObjectMapperBuilder,它透過以下屬性自定義 Jackson 的預設屬性
如果類路徑上檢測到以下眾所周知的模組,它還會自動註冊它們
-
jackson-datatype-jsr310:支援 Java 8 日期和時間 API 型別。 -
jackson-datatype-jdk8:支援其他 Java 8 型別,例如Optional。 -
jackson-module-kotlin:支援 Kotlin 類和資料類。
檢視解析器
以下示例展示瞭如何配置檢視解析
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
// ...
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
// ...
}
}
ViewResolverRegistry 提供了 Spring 框架整合的檢視技術的快捷方式。以下示例使用了 FreeMarker(這還需要配置底層 FreeMarker 檢視技術)
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.freeMarker();
}
// Configure Freemarker...
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("classpath:/templates");
return configurer;
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.freeMarker()
}
// Configure Freemarker...
@Bean
fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
setTemplateLoaderPath("classpath:/templates")
}
}
您還可以插入任何 ViewResolver 實現,示例如下
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
ViewResolver resolver = ... ;
registry.viewResolver(resolver);
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
val resolver: ViewResolver = ...
registry.viewResolver(resolver
}
}
為了支援 內容協商 並透過檢視解析(除了 HTML)渲染其他格式,您可以配置一個或多個基於 HttpMessageWriterView 實現的預設檢視,該實現接受 spring-web 中任何可用的 編解碼器。以下示例展示瞭如何實現:
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.freeMarker();
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
registry.defaultViews(new HttpMessageWriterView(encoder));
}
// ...
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.freeMarker()
val encoder = Jackson2JsonEncoder()
registry.defaultViews(HttpMessageWriterView(encoder))
}
// ...
}
有關與 Spring WebFlux 整合的檢視技術的更多資訊,請參閱 檢視技術。
靜態資源
此選項提供了一種便捷的方式,可以從基於 Resource 的位置列表中提供靜態資源。
在下一個示例中,給定一個以 /resources 開頭的請求,相對路徑用於查詢並提供相對於類路徑上 /static 的靜態資源。資源的過期時間設定為一年,以確保最大限度地利用瀏覽器快取並減少瀏覽器發出的 HTTP 請求。還會評估 Last-Modified 標頭,如果存在,則返回 304 狀態碼。以下列表顯示了該示例
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public", "classpath:/static/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public", "classpath:/static/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
}
}
另請參見 靜態資源的 HTTP 快取支援。
資源處理器還支援 ResourceResolver 實現鏈和 ResourceTransformer 實現鏈,可用於建立用於處理最佳化資源的工具鏈。
你可以使用 VersionResourceResolver,它根據內容的 MD5 雜湊、固定的應用程式版本或其他資訊,為帶版本的資源 URL 生成版本。ContentVersionStrategy (MD5 雜湊) 是一個不錯的選擇,但有一些明顯的例外 (例如與模組載入器一起使用的 JavaScript 資源)。
以下示例展示瞭如何在 Java 配置中使用 VersionResourceResolver
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public/")
.resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public/")
.resourceChain(true)
.addResolver(VersionResourceResolver().addContentVersionStrategy("/**"))
}
}
你可以使用 ResourceUrlProvider 來重寫 URL 並應用完整的解析器和轉換器鏈(例如,插入版本)。WebFlux 配置提供了一個 ResourceUrlProvider,以便可以將其注入到其他元件中。
與 Spring MVC 不同,目前在 WebFlux 中,無法透明地重寫靜態資源 URL,因為沒有檢視技術可以利用非阻塞的解析器和轉換器鏈。當僅提供本地資源時,解決方法是直接使用 ResourceUrlProvider(例如,透過自定義元素)並阻塞。
請注意,當同時使用 EncodedResourceResolver(例如,Gzip、Brotli 編碼)和 VersionedResourceResolver 時,它們必須按此順序註冊,以確保基於內容的版本始終基於未編碼的檔案可靠地計算。
對於 WebJars,帶版本號的 URL,例如 /webjars/jquery/1.2.0/jquery.min.js 是使用它們的推薦且最有效的方式。相關的資源位置在 Spring Boot 中開箱即用(或者可以透過 ResourceHandlerRegistry 手動配置),並且不需要新增 org.webjars:webjars-locator-lite 依賴。
無版本號的 URL,例如 /webjars/jquery/jquery.min.js,透過 WebJarsResourceResolver 支援,當類路徑中存在 org.webjars:webjars-locator-lite 庫時,該解析器會自動註冊。該解析器可以重寫 URL 以包含 jar 的版本,並且還可以匹配沒有版本號的傳入 URL——例如,將 /webjars/jquery/jquery.min.js 匹配到 /webjars/jquery/1.2.0/jquery.min.js。
基於 ResourceHandlerRegistry 的 Java 配置提供了更多細粒度控制選項,例如,最後修改行為和最佳化的資源解析。 |
路徑匹配
您可以自定義與路徑匹配相關的選項。有關各個選項的詳細資訊,請參閱 PathMatchConfigurer javadoc。以下示例展示瞭如何使用 PathMatchConfigurer
-
Java
-
Kotlin
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerTypePredicate;
import org.springframework.web.reactive.config.PathMatchConfigurer;
import org.springframework.web.reactive.config.WebFluxConfigurer;
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void configurePathMatching(PathMatchConfigurer configurer) {
configurer.addPathPrefix(
"/api", HandlerTypePredicate.forAnnotation(RestController.class));
}
}
import org.springframework.context.annotation.Configuration
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.method.HandlerTypePredicate
import org.springframework.web.reactive.config.PathMatchConfigurer
import org.springframework.web.reactive.config.WebFluxConfigurer
@Configuration
class WebConfig : WebFluxConfigurer {
override fun configurePathMatching(configurer: PathMatchConfigurer) {
configurer.addPathPrefix(
"/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
}
}
|
Spring WebFlux 依賴於請求路徑的解析表示(稱為 Spring WebFlux 也不支援字尾模式匹配,與 Spring MVC 不同,在 Spring MVC 中,我們也 建議 放棄對其的依賴。 |
API 版本
要啟用 API 版本控制,請使用 WebFluxConfigurer 的 ApiVersionConfigurer 回撥
-
Java
-
Kotlin
@Configuration
public class WebConfiguration implements WebFluxConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
configurer.useRequestHeader("API-Version");
}
}
@Configuration
class WebConfiguration : WebMvcConfigurer {
override fun configureApiVersioning(configurer: ApiVersionConfigurer) {
configurer.useRequestHeader("API-Version")
}
}
您可以透過以下內建選項之一解析版本,或者使用自定義的 ApiVersionResolver
-
請求頭
-
請求引數
-
路徑段
-
媒體型別引數
要從路徑段解析,您需要指定預期包含版本的路徑段的索引。路徑段必須宣告為 URI 變數,例如“/{version}”、“/api/{version}”等,其中實際名稱不重要。由於版本通常位於路徑的開頭,請考慮透過 路徑匹配 選項將其外部配置為所有處理程式的公共路徑字首。
預設情況下,版本透過 SemanticVersionParser 解析,但您也可以配置自定義的 ApiVersionParser。
為了方便起見,WebFlux 會透明地從請求對映中宣告的版本中檢測支援的版本,但您可以透過 WebFlux 配置中的一個標誌將其關閉,並僅將配置中明確配置的版本視為支援的版本。帶有不支援版本的請求將被 InvalidApiVersionException 拒絕,並導致 400 響應。
您可以設定一個 ApiVersionDeprecationHandler 來向客戶端傳送有關已棄用版本的資訊。內建的標準處理程式可以根據 RFC 9745 和 RFC 8594 設定“Deprecation”、“Sunset”和“Link”標頭。
一旦配置了 API 版本控制,您就可以根據請求版本將請求對映到 控制器方法。
阻塞執行
WebFlux Java 配置允許您自定義 WebFlux 中的阻塞執行。
透過提供 AsyncTaskExecutor(例如 VirtualThreadTaskExecutor),您可以將阻塞控制器方法在單獨的執行緒上呼叫,如下所示
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureBlockingExecution(BlockingExecutionConfigurer configurer) {
AsyncTaskExecutor executor = ...
configurer.setExecutor(executor);
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
@Override
fun configureBlockingExecution(configurer: BlockingExecutionConfigurer) {
val executor = ...
configurer.setExecutor(executor)
}
}
預設情況下,返回型別未被已配置的 ReactiveAdapterRegistry 識別的控制器方法被認為是阻塞的,但您可以透過 BlockingExecutionConfigurer 設定自定義控制器方法謂詞。
WebSocketService
WebFlux Java 配置聲明瞭一個 WebSocketHandlerAdapter bean,它提供了對 WebSocket 處理器呼叫的支援。這意味著,為了處理 WebSocket 握手請求,所有需要做的就是透過 SimpleUrlHandlerMapping 將 WebSocketHandler 對映到一個 URL。
在某些情況下,可能需要使用提供的 WebSocketService 服務來建立 WebSocketHandlerAdapter bean,該服務允許配置 WebSocket 伺服器屬性。例如
-
Java
-
Kotlin
@Configuration
public class WebConfig implements WebFluxConfigurer {
@Override
public WebSocketService getWebSocketService() {
TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
strategy.setMaxSessionIdleTimeout(0L);
return new HandshakeWebSocketService(strategy);
}
}
@Configuration
class WebConfig : WebFluxConfigurer {
@Override
fun webSocketService(): WebSocketService {
val strategy = TomcatRequestUpgradeStrategy().apply {
setMaxSessionIdleTimeout(0L)
}
return HandshakeWebSocketService(strategy)
}
}
高階配置模式
@EnableWebFlux 匯入 DelegatingWebFluxConfiguration,它
-
為 WebFlux 應用程式提供預設的 Spring 配置
-
檢測並委託給
WebFluxConfigurer實現以自定義該配置。
對於高階模式,你可以移除 @EnableWebFlux 並直接從 DelegatingWebFluxConfiguration 繼承,而不是實現 WebFluxConfigurer,示例如下
-
Java
-
Kotlin
@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {
// ...
}
@Configuration
class WebConfig : DelegatingWebFluxConfiguration {
// ...
}
你可以保留 WebConfig 中現有的方法,但現在你也可以覆蓋基類中的 bean 宣告,並且仍然可以在類路徑上擁有任意數量的其他 WebMvcConfigurer 實現。