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 时,您可能希望使用 |
前面的例子注册了许多 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)
}
}
|
有关何时使用 |
验证
默认情况下,如果类路径上存在 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())
}
}
|
如果您需要注入 |
内容类型解析器
您可以配置 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 的默认属性:
如果检测到类路径上有以下众所周知的模块,它还会自动注册它们:
-
jackson-datatype-jsr310:支持 Java 8 日期和时间 API 类型。 -
jackson-datatype-jdk8:支持其他 Java 8 类型,例如Optional。 -
jackson-module-kotlin:支持 Kotlin 类和数据类。
视图解析器
以下示例展示了如何配置视图解析:
-
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))
}
}
另请参见 静态资源的 HTTP 缓存支持。
资源处理器还支持 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。
|
基于 |
路径匹配
您可以自定义与路径匹配相关的选项。有关各个选项的详细信息,请参阅 PathMatchConfigurer javadoc。以下示例展示了如何使用 PathMatchConfigurer:
|
Spring WebFlux 依赖于请求路径的解析表示,称为 |
API 版本
要启用 API 版本控制,请使用 WebFluxConfigurer 的 ApiVersionConfigurer 回调:
-
Java
-
Kotlin
@Configuration
public class WebConfiguration implements WebFluxConfigurer {
@Override
public void configureApiVersioning(ApiVersionConfigurer configurer) {
configurer.useRequestHeader("X-API-Version");
}
}
@Configuration
class WebConfiguration : WebMvcConfigurer {
override fun configureApiVersioning(configurer: ApiVersionConfigurer) {
configurer.useRequestHeader("X-API-Version")
}
}
您可以通过下面列出的内置选项之一解析版本,或者使用自定义 ApiVersionResolver:
-
请求头
-
请求参数
-
路径段
-
媒体类型参数
要从路径段解析,您需要指定预期包含版本的路径段的索引。路径段必须声明为 URI 变量,例如 "/{version}"、"/api/{version}" 等,其中实际名称并不重要。 由于版本通常位于路径的开头,请考虑通过 路径匹配 选项将其作为所有处理程序的通用路径前缀进行外部配置。
默认情况下,版本使用 SemanticVersionParser 解析,但您也可以配置自定义 ApiVersionParser。
支持的版本会从请求映射中声明的版本中透明地检测出来,以方便使用,但您可以通过 WebFlux 配置中的一个标志将其关闭,并只考虑配置中明确配置的版本为支持的版本。
版本不受支持的请求将被 InvalidApiVersionException 拒绝,导致 400 响应。
您可以设置 ApiVersionDeprecationHandler 以向客户端发送有关已弃用版本的信息。内置的标准处理程序可以根据 RFC 9745 和 RFC 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 握手请求,所有需要做的就是通过 SimpleUrlHandlerMapping 将 WebSocketHandler 映射到 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 实现。