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 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 框架集成的视图技术的快捷方式。以下示例使用了 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-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 依赖于请求路径的解析表示(称为 RequestPath)来访问已解码的路径段值,并去除了分号内容(即路径或矩阵变量)。这意味着,与 Spring MVC 不同,您无需指示是否解码请求路径,也无需指示是否为路径匹配目的去除分号内容。

Spring WebFlux 也不支持后缀模式匹配,与 Spring MVC 不同,在 Spring MVC 中,我们也 建议 放弃对其的依赖。

API 版本

要启用 API 版本控制,请使用 WebFluxConfigurerApiVersionConfigurer 回调

  • 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 9745RFC 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 握手请求,所有需要做的就是通过 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 实现。

© . This site is unofficial and not affiliated with VMware.