WebFlux Config

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

The WebFlux Java configuration declares the components that are required to process requests with annotated controllers or functional endpoints, and it offers an API to customize the configuration. That means you do not need to understand the underlying beans created by the Java configuration. However, if you want to understand them, you can see them in WebFluxConfigurationSupport or read more about what they are in Special Bean Types.

对于配置 API 中不可用的更高级的自定义,您可以通过 Advanced Configuration Mode 完全控制配置。

For more advanced customizations, not available in the configuration API, you can gain full control over the configuration through the Advanced Configuration Mode.

Enabling WebFlux Config

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

You can use the @EnableWebFlux annotation in your Java config, as the following example shows:

  • 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 文档

When using Spring Boot, you may want to use @Configuration classes of type WebFluxConfigurer but without @EnableWebFlux to keep Spring Boot WebFlux customizations. See more details in webflux-config-customize and in the dedicated Spring Boot documentation.

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

The preceding example registers a number of Spring WebFlux infrastructure beans and adapts to dependencies available on the classpath — for JSON, XML, and others.

WebFlux config API

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

In your Java configuration, you can implement the WebFluxConfigurer interface, as the following example shows:

  • Java

  • Kotlin

@Configuration
public class WebConfig implements WebFluxConfigurer {

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

	// Implement configuration methods...
}

Conversion, formatting

在默认情况下,也会安装各种数字和日期类型的格式化程序,以及通过字段中的 @NumberFormat@DateTimeFormat 自定义的支持。

By default, formatters for various number and date types are installed, along with support for customization via @NumberFormat and @DateTimeFormat on fields.

要在 Java 配置中注册自定义格式化程序和转换器,请使用以下信息:

To register custom formatters and converters in Java config, use the following:

  • 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 规范中定义的固定格式。对于此类情况,日期和时间格式化可以按照如下方式自定义:

By default Spring WebFlux considers the request Locale when parsing and formatting date values. This works for forms where dates are represented as Strings with "input" form fields. For "date" and "time" form fields, however, browsers use a fixed format defined in the HTML spec. For such cases date and time formatting can be customized as follows:

  • 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

See FormatterRegistrar SPI and the FormattingConversionServiceFactoryBean for more information on when to use FormatterRegistrar implementations.

Validation

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

By default, if Bean Validation is present on the classpath (for example, the Hibernate Validator), the LocalValidatorFactoryBean is registered as a global validator for use with @Valid and @Validated on @Controller method arguments.

在 Java 配置中,您可以自定义全局 Validator 实例,如下所示:

In your Java configuration, you can customize the global Validator instance, as the following example shows:

  • Java

  • Kotlin

@Configuration
public class WebConfig implements WebFluxConfigurer {

	@Override
	public Validator getValidator() {
		// ...
	}

}
@Configuration
class WebConfig : WebFluxConfigurer {

	override fun getValidator(): Validator {
		// ...
	}

}

请注意,您还可以按照如下所示局部注册 Validator 实现:

Note that you can also register Validator implementations locally, as the following example shows:

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

If you need to have a LocalValidatorFactoryBean injected somewhere, create a bean and mark it with @Primary in order to avoid conflict with the one declared in the MVC config.

Content Type Resolvers

您可以配置 Spring WebFlux 如何从请求中确定 @Controller 实例的请求媒体类型。默认情况下,仅检查 Accept 标头,但您还可以启用基于查询参数的策略。

You can configure how Spring WebFlux determines the requested media types for @Controller instances from the request. By default, only the Accept header is checked, but you can also enable a query parameter-based strategy.

以下示例显示如何自定义请求内容类型解析:

The following example shows how to customize the requested content type resolution:

  • 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

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

The following example shows how to customize how the request and response body are read and written:

  • 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 提供了一组默认读取器和写入器。您可以使用它来添加更多读取器和写入器,自定义默认读取器和写入器,或完全替换默认读取器和写入器。

ServerCodecConfigurer provides a set of default readers and writers. You can use it to add more readers and writers, customize the default ones, or replace the default ones completely.

对于 Jackson JSON 和 XML,考虑使用 Jackson2ObjectMapperBuilder,它使用以下配置定制 Jackson 的默认属性:

For Jackson JSON and XML, consider using Jackson2ObjectMapperBuilder, which customizes Jackson’s default properties with the following ones:

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

It also automatically registers the following well-known modules if they are detected on the classpath:

View Resolvers

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

The following example shows how to configure view resolution:

  • 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 视图技术):

The ViewResolverRegistry has shortcuts for view technologies with which the Spring Framework integrates. The following example uses FreeMarker (which also requires configuring the underlying FreeMarker view technology):

  • 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 实现,如下面的示例所示:

You can also plug in any ViewResolver implementation, as the following example shows:

  • 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。以下示例展示了如何执行此操作:

To support Content Negotiation and rendering other formats through view resolution (besides HTML), you can configure one or more default views based on the HttpMessageWriterView implementation, which accepts any of the available Codecs from spring-web. The following example shows how to do so:

  • 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 集成的视图技术。

See View Technologies for more on the view technologies that are integrated with Spring WebFlux.

Static Resources

此选项提供了一种方便的方法来基于一组https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/io/Resource.html[Resource] 位置提供静态资源。

This option provides a convenient way to serve static resources from a list of Resource-based locations.

在下一个示例中,给定从 /resources 开始的请求,将使用相对路径在类路径上的 /static 相对于查找并提供静态资源。提供资源时将会有一年的未来到期时间,以确保最大程度地利用浏览器缓存并减少浏览器发出的 HTTP 请求。还将计算 Last-Modified 标头,如果存在,则返回 304 状态代码。以下列表显示了该示例:

In the next example, given a request that starts with /resources, the relative path is used to find and serve static resources relative to /static on the classpath. Resources are served with a one-year future expiration to ensure maximum use of the browser cache and a reduction in HTTP requests made by the browser. The Last-Modified header is also evaluated and, if present, a 304 status code is returned. The following listing shows the example:

  • 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]”实现的链,可用来创建工具链,以便处理经过优化的资源。

The resource handler also supports a chain of ResourceResolver implementations and ResourceTransformer implementations, which can be used to create a toolchain for working with optimized resources.

可以将 VersionResourceResolver 用于基于内容 MD5 哈希、固定应用程序版本或其他信息的版本化资源 URL。ContentVersionStrategy(MD5 哈希)是一个不错的选择,但有一些值得注意的例外(例如与模块加载器一起使用的 JavaScript 资源)。

You can use the VersionResourceResolver for versioned resource URLs based on an MD5 hash computed from the content, a fixed application version, or other information. A ContentVersionStrategy (MD5 hash) is a good choice with some notable exceptions (such as JavaScript resources used with a module loader).

以下示例展示如何在 Java 配置中使用 VersionResourceResolver

The following example shows how to use VersionResourceResolver in your Java configuration:

  • 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,以便可以将其注入到其他资源中。

You can use ResourceUrlProvider to rewrite URLs and apply the full chain of resolvers and transformers (for example, to insert versions). The WebFlux configuration provides a ResourceUrlProvider so that it can be injected into others.

与 Spring MVC 不同,目前在 WebFlux 中,没有办法透明地重写静态资源 URL,因为没有视图技术可以利用非阻塞解析器和转换器链。仅提供本地资源时,变通办法是使用 ResourceUrlProvider(例如,通过自定义元素)并阻塞。

Unlike Spring MVC, at present, in WebFlux, there is no way to transparently rewrite static resource URLs, since there are no view technologies that can make use of a non-blocking chain of resolvers and transformers. When serving only local resources, the workaround is to use ResourceUrlProvider directly (for example, through a custom element) and block.

请注意,当同时使用 EncodedResourceResolver(例如,Gzip、Brotli 编码)和 VersionedResourceResolver 时,必须按该顺序注册它们,以确保始终根据未编码文件可靠地计算基于内容的版本。

Note that, when using both EncodedResourceResolver (for example, Gzip, Brotli encoded) and VersionedResourceResolver, they must be registered in that order, to ensure content-based versions are always computed reliably based on the unencoded file.

对于 WebJars,推荐使用版本化 URL,例如`/webjars/jquery/1.2.0/jquery.min.js`,并且是使用它们的最有效方法。上述资源位置在 Spring Boot 外部已配置(或可通过`ResourceHandlerRegistry`手动进行配置),并且无需添加`org.webjars:webjars-locator-core`依赖项。

For WebJars, versioned URLs like /webjars/jquery/1.2.0/jquery.min.js are the recommended and most efficient way to use them. The related resource location is configured out of the box with Spring Boot (or can be configured manually via ResourceHandlerRegistry) and does not require to add the org.webjars:webjars-locator-core dependency.

通过 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

Version-less URLs like /webjars/jquery/jquery.min.js are supported through the WebJarsResourceResolver which is automatically registered when the org.webjars:webjars-locator-core library is present on the classpath, at the cost of a classpath scanning that could slow down application startup. The resolver can re-write URLs to include the version of the jar and can also match against incoming URLs without versions — for example, from /webjars/jquery/jquery.min.js to /webjars/jquery/1.2.0/jquery.min.js.

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

The Java configuration based on ResourceHandlerRegistry provides further options for fine-grained control, e.g. last-modified behavior and optimized resource resolution.

Path Matching

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

You can customize options related to path matching. For details on the individual options, see the PathMatchConfigurer javadoc. The following example shows how to use 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 WebFlux relies on a parsed representation of the request path called RequestPath for access to decoded path segment values, with semicolon content removed (that is, path or matrix variables). That means, unlike in Spring MVC, you need not indicate whether to decode the request path nor whether to remove semicolon content for path matching purposes.

与 Spring MVC 不同,Spring WebFlux 也不支持后缀模式匹配,在 Spring MVC 中,我们也在 recommend 远离依赖它。

Spring WebFlux also does not support suffix pattern matching, unlike in Spring MVC, where we are also recommend moving away from reliance on it.

Blocking Execution

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

The WebFlux Java config allows you to customize blocking execution in WebFlux.

你可以通过提供一个 AsyncTaskExecutor,例如“https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/task/VirtualThreadTaskExecutor.html[VirtualThreadTaskExecutor]”,以便在独立的线程上调用阻塞控制器方法,如下所示:

You can have blocking controller methods called on a separate thread by providing an AsyncTaskExecutor such as the VirtualThreadTaskExecutor as follows:

  • 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 设置自定义控制器方法谓词。

By default, controller methods whose return type is not recognized by the configured ReactiveAdapterRegistry are considered blocking, but you can set a custom controller method predicate via BlockingExecutionConfigurer.

WebSocketService

WebFlux Java 配置声明一个 WebSocketHandlerAdapter bean,它为 WebSocket 处理程序的调用提供支持。这意味着要处理 WebSocket 握手请求,剩下的就是通过 SimpleUrlHandlerMappingWebSocketHandler 映射到 URL。

The WebFlux Java config declares of a WebSocketHandlerAdapter bean which provides support for the invocation of WebSocket handlers. That means all that remains to do in order to handle a WebSocket handshake request is to map a WebSocketHandler to a URL via SimpleUrlHandlerMapping.

在某些情况下,可能需要使用提供的 WebSocketService 服务创建 WebSocketHandlerAdapter bean,它允许配置 WebSocket 服务器属性。例如:

In some cases it may be necessary to create the WebSocketHandlerAdapter bean with a provided WebSocketService service which allows configuring WebSocket server properties. For example:

  • 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

@EnableWebFlux imports DelegatingWebFluxConfiguration that:

  • Provides default Spring configuration for WebFlux applications

  • detects and delegates to WebFluxConfigurer implementations to customize that configuration.

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

For advanced mode, you can remove @EnableWebFlux and extend directly from DelegatingWebFluxConfiguration instead of implementing WebFluxConfigurer, as the following example shows:

  • Java

  • Kotlin

@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {

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

	// ...
}

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

You can keep existing methods in WebConfig, but you can now also override bean declarations from the base class and still have any number of other WebMvcConfigurer implementations on the classpath.