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 SPIFormattingConversionServiceFactoryBean,以取得有關何時使用 FormatterRegistrar 實作的更多資訊。

驗證

預設情況下,如果 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 訊息編解碼器

下列範例示範如何自訂讀取和寫入請求和回應 Body 的方式

  • 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 框架整合的視圖技術的捷徑。下列範例使用 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 實作鏈,可用於建立工具鏈以處理最佳化資源。

您可以針對基於從內容計算出的 MD5 雜湊、固定應用程式版本或其他資訊的版本化資源 URL 使用 VersionResourceResolverContentVersionStrategy (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 MVC 不同,Spring WebFlux 也不支援後綴模式匹配,在 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 宣告,並且在類別路徑上仍然可以有任意數量的其他 WebMvcConfigurer 實作。