WebFlux 配置
WebFlux Java 配置声明了使用带注解的控制器或函数式端点处理请求所需的组件,并提供了一个用于自定义配置的 API。这意味着您无需了解 Java 配置创建的底层 beans。但是,如果您想了解它们,可以在 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 在解析和格式化日期值时会考虑请求的 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)
}
}
有关何时使用 FormatterRegistrar 实现的更多信息,请参阅 FormatterRegistrar SPI 和 FormattingConversionServiceFactoryBean 。 |
验证
默认情况下,如果类路径上存在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 的默认属性
如果在类路径上检测到以下知名模块,它还会自动注册
-
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-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 依赖于名为 Spring WebFlux 也不支持后缀模式匹配,与 Spring MVC 不同,我们在 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 握手请求,只需通过 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 声明,并且仍然可以在 classpath 中拥有任意数量的其他 WebMvcConfigurer
实现。