WebFlux 配置

WebFlux Java 配置聲明瞭使用帶註解的控制器或函式式端點處理請求所需的元件,並提供了一個用於自定義配置的 API。這意味著您無需瞭解 Java 配置建立的底層 beans。但是,如果您想了解它們,可以在 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 在解析和格式化日期值時會考慮請求的 Locale。這適用於透過“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 SPIFormattingConversionServiceFactoryBean

驗證

預設情況下,如果類路徑上存在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 的預設屬性

如果在類路徑上檢測到以下知名模組,它還會自動註冊

檢視解析器

以下示例展示瞭如何配置檢視解析

  • 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 Framework 整合的檢視技術的快捷方式。以下示例使用 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))
	}
}

資源處理器還支援一個由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-core 依賴。

不帶版本的 URL,如 /webjars/jquery/jquery.min.js,透過 WebJarsResourceResolver 支援,當類路徑上存在 org.webjars:webjars-locator-core 庫時,它會自動註冊,代價是類路徑掃描可能會減慢應用啟動速度。該解析器可以重寫 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 依賴於名為 RequestPath 的請求路徑解析表示,用於訪問解碼的路徑段值,並去除分號內容(即路徑或矩陣變數)。這意味著,與 Spring MVC 不同,您無需指定是否解碼請求路徑或是否移除分號內容用於路徑匹配。

Spring WebFlux 也不支援字尾模式匹配,與 Spring MVC 不同,我們在 Spring MVC 中也建議不再依賴它。

阻塞執行

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 握手請求,只需透過 SimpleUrlHandlerMappingWebSocketHandler 對映到 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 宣告,並且仍然可以在 classpath 中擁有任意數量的其他 WebMvcConfigurer 實現。