WebFlux Config

WebFlux Java 配置声明了处理带注释控制器或功能端点请求所需的组件,并提供了一个 API 来自定义配置。这意味着您无需了解 Java 配置创建的底层 Bean。但是,如果您想了解它们,可以在 WebFluxConfigurationSupport 中查看,或者在 Special Bean Types 中阅读更多有关它们的信息。 对于配置 API 中不可用的更高级的自定义,您可以通过 Advanced Configuration Mode 完全控制配置。

Enabling WebFlux Config

你可以在你的 Java 配置中使用 @EnableWebFlux 注释,如下例所示:

  • Java

  • Kotlin

@Configuration
@EnableWebFlux
public class WebConfig {
}
@Configuration
@EnableWebFlux
class WebConfig

在使用 Spring Boot 时,您可能希望使用类型为 WebFluxConfigurer@Configuration 类,但不用 @EnableWebFlux 来保留 Spring Boot WebFlux 自定义项。有关更多详细信息,请参阅 the WebFlux config API section专门的 Spring Boot 文档

前面的示例注册了许多 Spring WebFlux infrastructure beans,并适应 classpath 上可用的依赖项——JSON、XML 等。

WebFlux config API

在 Java 配置中,您可以实现 WebFluxConfigurer 接口,如下所示:

  • Java

  • Kotlin

@Configuration
public class WebConfig implements WebFluxConfigurer {

	// Implement configuration methods...
}
@Configuration
class WebConfig : WebFluxConfigurer {

	// Implement configuration methods...
}

Conversion, formatting

在默认情况下,也会安装各种数字和日期类型的格式化程序,以及通过字段中的 @NumberFormat@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

Validation

默认情况下,如果 Bean Validation 存在于 classpath 中(例如,Hibernate Validator),则 LocalValidatorFactoryBean 将注册为一个全局 validator,以用于 @Valid@Validated 中的 @Controller 方法参数。

在 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 冲突。

Content Type Resolvers

您可以配置 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 message codecs

以下示例显示如何自定义请求和响应正文的读取和写入方式:

  • 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 的默认属性:

如果在类路径中检测到以下著名的模块,它还将自动注册这些模块:

View Resolvers

以下示例显示如何配置视图解析:

  • 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
	}
}

要支持 Content Negotiation 并通过视图解析(除了 HTML)呈现其他格式,您可以根据 HttpMessageWriterView 实现配置一个或多个默认视图,该实现接受来自 spring-web 的任何可用的 Codecs。以下示例展示了如何执行此操作:

  • 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))
	}

	// ...
}

请参阅 View Technologies 以详细了解与 Spring WebFlux 集成的视图技术。

Static Resources

此选项提供了一种方便的方法来基于一组https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/io/Resource.html[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))
	}
}

资源处理程序还支持“https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/resource/ResourceResolver.html[ResourceResolver]”实现和“https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/resource/ResourceTransformer.html[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`依赖项。

通过 WebJarsResourceResolver 支持像 /webjars/jquery/jquery.min.js 这样的非版本化 URL,当 org.webjars:webjars-locator-core 库存在类路径中时,该解析器会自动注册,而代价是可能会减慢应用程序启动的类路径扫描。该解析器可以重写 URL 以包含 JAR 的版本,并且还可以匹配不带版本号的传入 URL——例如,从 /webjars/jquery/jquery.min.js 匹配到 /webjars/jquery/1.2.0/jquery.min.js

基于 ResourceHandlerRegistry 的 Java 配置提供了更多针对细粒度控制的选项,例如,最后修改行为和优化的资源解析。

Path Matching

你可以自定义与路径匹配相关的选项。有关单个选项的详细信息,请参阅“https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/config/PathMatchConfigurer.html[PathMatchConfigurer]”javadoc。以下示例展示了如何使用“PathMatchConfigurer”:

  • Java

  • Kotlin

@Configuration
public class WebConfig implements WebFluxConfigurer {

	@Override
	public void configurePathMatch(PathMatchConfigurer configurer) {
		configurer.addPathPrefix(
				"/api", HandlerTypePredicate.forAnnotation(RestController.class));
	}
}
@Configuration
class WebConfig : WebFluxConfigurer {

	@Override
	fun configurePathMatch(configurer: PathMatchConfigurer) {
		configurer.addPathPrefix(
				"/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
	}
}

Spring WebFlux 依赖请求路径的已解析表示形式,称为 RequestPath,用于访问已解码路径段值,并删除分号内容(即路径或矩阵变量)。这意味着,与 Spring MVC 不同,无需指明是否解码请求路径,也无需指明是否为了路径匹配目的而删除分号内容。 与 Spring MVC 不同,Spring WebFlux 也不支持后缀模式匹配,在 Spring MVC 中,我们也在 recommend 远离依赖它。

Blocking Execution

WebFlux Java 配置允许你自定义 WebFlux 中的阻塞执行。

你可以通过提供一个 AsyncTaskExecutor,例如“https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/task/VirtualThreadTaskExecutor.html[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)
	}
}

Advanced Configuration Mode

@EnableWebFlux 导入 DelegatingWebFluxConfiguration

  • 为 WebFlux 应用程序提供默认 Spring 配置

  • 检测并委托给`WebFluxConfigurer`实现以自定义该配置。

对于高级模式,您可以移除 @EnableWebFlux 并直接扩展自 DelegatingWebFluxConfiguration,而不是实现 WebFluxConfigurer,如下例所示:

  • Java

  • Kotlin

@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {

	// ...
}
@Configuration
class WebConfig : DelegatingWebFluxConfiguration {

	// ...
}

您可以在 WebConfig 中保留现有方法,但现在您还可以覆盖基础类的 bean 声明,并在类路径上仍然拥有任意数量的其他 WebMvcConfigurer 实现。