对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

WebFlux 配置

WebFlux 的 Java 配置声明了处理带注解控制器或函数式端点请求所需的组件,并提供了一个用于自定义配置的 API。这意味着您无需了解 Java 配置所创建的底层 Bean。不过,如果您希望了解这些 Bean,可以在 WebFluxConfigurationSupport 中查看,或在特殊 Bean 类型中阅读更多相关内容。spring-doc.cadn.net.cn

对于配置 API 中未提供的更高级自定义需求,您可以通过高级配置模式完全掌控配置。spring-doc.cadn.net.cn

启用 WebFlux 配置

您可以在 Java 配置中使用 @EnableWebFlux 注解,如下例所示:spring-doc.cadn.net.cn

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

前面的示例注册了多个 Spring WebFlux 基础架构 Bean,并根据类路径上可用的依赖项(如 JSON、XML 等)进行适配。spring-doc.cadn.net.cn

WebFlux 配置 API

在您的 Java 配置中,您可以实现 WebFluxConfigurer 接口,如下例所示:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

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

	// Implement configuration methods...
}

转换、格式化

默认情况下,系统会安装各种数字和日期类型的格式化器,并支持通过在字段上使用 @NumberFormat@DateTimeFormat 进行自定义。spring-doc.cadn.net.cn

要在 Java 配置中注册自定义的格式化器(formatters)和转换器(converters),请使用以下方式:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

	@Override
	public void addFormatters(FormatterRegistry registry) {
		// ...
	}

}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun addFormatters(registry: FormatterRegistry) {
		// ...
	}
}

默认情况下,Spring WebFlux 在解析和格式化日期值时会考虑请求的区域设置(Locale)。这适用于表单中使用 "input" 表单字段以字符串形式表示日期的情况。然而,对于 "date" 和 "time" 表单字段,浏览器会使用 HTML 规范中定义的固定格式。针对此类情况,可以按如下方式自定义日期和时间的格式化:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

	@Override
	public void addFormatters(FormatterRegistry registry) {
		DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
		registrar.setUseIsoFormat(true);
		registrar.registerFormatters(registry);
     	}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun addFormatters(registry: FormatterRegistry) {
		val registrar = DateTimeFormatterRegistrar()
		registrar.setUseIsoFormat(true)
		registrar.registerFormatters(registry)
	}
}
请参阅 FormatterRegistrar SPI 以及 FormattingConversionServiceFactoryBean,以获取更多关于何时使用 FormatterRegistrar 实现的信息。

验证

默认情况下,如果类路径中存在Bean Validation(例如 Hibernate Validator),则会将LocalValidatorFactoryBean注册为全局验证器,用于在@Valid方法参数上配合@Validated@Controller使用。spring-doc.cadn.net.cn

在您的 Java 配置中,您可以自定义全局的 Validator 实例,如下例所示:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

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

}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

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

}

请注意,您也可以注册本地的 Validator 实现,如下例所示:spring-doc.cadn.net.cn

@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 配置中声明的那个发生冲突。

内容类型解析器

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

以下示例展示了如何自定义请求的内容类型解析:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

	@Override
	public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
		// ...
	}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun configureContentTypeResolver(builder: RequestedContentTypeResolverBuilder) {
		// ...
	}
}

HTTP 消息编解码器

以下示例展示了如何自定义请求和响应正文的读取与写入方式:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

	@Override
	public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
		configurer.defaultCodecs().maxInMemorySize(512 * 1024);
	}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
		// ...
	}
}

ServerCodecConfigurer 提供了一组默认的读取器和写入器。您可以使用它来添加更多的读取器和写入器、自定义默认的读取器和写入器,或者完全替换默认的读取器和写入器。spring-doc.cadn.net.cn

对于 Jackson JSON 和 XML,建议考虑使用 Jackson2ObjectMapperBuilder, 它通过以下配置自定义了 Jackson 的默认属性:spring-doc.cadn.net.cn

如果在类路径中检测到以下知名模块,它还会自动注册这些模块:spring-doc.cadn.net.cn

视图解析器

以下示例展示了如何配置视图解析:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		// ...
	}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun configureViewResolvers(registry: ViewResolverRegistry) {
		// ...
	}
}

ViewResolverRegistry 为 Spring 框架集成的视图技术提供了快捷方式。以下示例使用了 FreeMarker(这还需要配置底层的 FreeMarker 视图技术):spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
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
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun configureViewResolvers(registry: ViewResolverRegistry) {
		registry.freeMarker()
	}

	// Configure Freemarker...

	@Bean
	fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
		setTemplateLoaderPath("classpath:/templates")
	}
}

你也可以插入任意的 ViewResolver 实现,如下例所示:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		ViewResolver resolver = ... ;
		registry.viewResolver(resolver);
	}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun configureViewResolvers(registry: ViewResolverRegistry) {
		val resolver: ViewResolver = ...
		registry.viewResolver(resolver
	}
}

为了支持内容协商并通过视图解析渲染其他格式(除 HTML 外),您可以基于HttpMessageWriterView实现配置一个或多个默认视图,该实现可接受来自xref page的任意可用编解码器(Codecs)。以下示例展示了如何进行此类配置:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.freeMarker();

		Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
		registry.defaultViews(new HttpMessageWriterView(encoder));
	}

	// ...
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {


	override fun configureViewResolvers(registry: ViewResolverRegistry) {
		registry.freeMarker()

		val encoder = Jackson2JsonEncoder()
		registry.defaultViews(HttpMessageWriterView(encoder))
	}

	// ...
}

有关与 Spring WebFlux 集成的视图技术的更多信息,请参阅视图技术spring-doc.cadn.net.cn

静态资源

此选项提供了一种便捷的方式,用于从基于 Resource的位置列表中提供静态资源。spring-doc.cadn.net.cn

在下一个示例中,对于以 /resources 开头的请求,将使用相对路径在类路径下的 /static 目录中查找并提供静态资源。这些资源设置了一年的未来过期时间,以确保浏览器缓存得到最大程度的利用,并减少浏览器发出的 HTTP 请求次数。同时还会检查 Last-Modified 响应头,如果存在,则返回 304 状态码。以下代码清单展示了该示例:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
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
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
		registry.addResourceHandler("/resources/**")
				.addResourceLocations("/public", "classpath:/static/")
				.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
	}
}

资源处理器还支持一系列 ResourceResolver 实现和 ResourceTransformer 实现, 可用于构建处理优化资源的工具链。spring-doc.cadn.net.cn

您可以使用 VersionResourceResolver,根据内容计算出的 MD5 哈希值、固定的应用程序版本或其他信息,为资源 URL 添加版本信息。ContentVersionStrategy(MD5 哈希)是一个不错的选择,但有一些明显的例外情况(例如与模块加载器一起使用的 JavaScript 资源)。spring-doc.cadn.net.cn

以下示例展示了如何在您的 Java 配置中使用 VersionResourceResolverspring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**")
				.addResourceLocations("/public/")
				.resourceChain(true)
				.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
	}

}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
		registry.addResourceHandler("/resources/**")
				.addResourceLocations("/public/")
				.resourceChain(true)
				.addResolver(VersionResourceResolver().addContentVersionStrategy("/**"))
	}

}

您可以使用 ResourceUrlProvider 来重写 URL,并应用完整的解析器和转换器链(例如,插入版本信息)。WebFlux 配置提供了一个 ResourceUrlProvider,以便可以将其注入到其他组件中。spring-doc.cadn.net.cn

与 Spring MVC 不同,目前在 WebFlux 中无法透明地重写静态资源 URL,因为尚无任何视图技术能够利用非阻塞的解析器和转换器链。当仅提供本地资源时,解决方法是直接使用 ResourceUrlProvider(例如,通过自定义元素),但这会导致阻塞。spring-doc.cadn.net.cn

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

对于WebJars,推荐使用带版本号的 URL,例如 /webjars/jquery/1.2.0/jquery.min.js,这是最高效的方式。 相关的资源位置在 Spring Boot 中已开箱即用(或可通过 ResourceHandlerRegistry 手动配置), 无需添加 org.webjars:webjars-locator-core 依赖。spring-doc.cadn.net.cn

通过 /webjars/jquery/jquery.min.js 支持无版本的 URL(例如 WebJarsResourceResolver)。当 classpath 中存在 org.webjars:webjars-locator-core 库时,该解析器会自动注册,但代价是进行 classpath 扫描,可能会减慢应用程序的启动速度。该解析器可以重写 URL 以包含 JAR 包的版本号,也可以匹配不带版本号的传入 URL——例如,将 /webjars/jquery/jquery.min.js 映射到 /webjars/jquery/1.2.0/jquery.min.jsspring-doc.cadn.net.cn

基于 ResourceHandlerRegistry 的 Java 配置提供了更多细粒度控制的选项,例如 last-modified 行为和优化的资源解析。

路径匹配

您可以自定义与路径匹配相关的选项。有关各个选项的详细信息,请参阅 PathMatchConfigurer javadoc。 以下示例展示了如何使用 PathMatchConfigurerspring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

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

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

Spring WebFlux 依赖于一种称为 RequestPath 的请求路径解析表示形式,用于访问已解码的路径段值,并移除了分号内容(即路径变量或矩阵变量)。这意味着,与 Spring MVC 不同,你无需指明是否对请求路径进行解码,也无需指明是否为路径匹配目的而移除分号内容。spring-doc.cadn.net.cn

与 Spring MVC 不同,Spring WebFlux 也不支持后缀模式匹配,而在 Spring MVC 中,我们也建议逐步摆脱对此特性的依赖。spring-doc.cadn.net.cn

WebSocket 服务

WebFlux 的 Java 配置声明了一个 WebSocketHandlerAdapter Bean,用于支持调用 WebSocket 处理器。这意味着要处理 WebSocket 握手请求,只需通过 WebSocketHandler 将一个 SimpleUrlHandlerMapping 映射到某个 URL 即可。spring-doc.cadn.net.cn

在某些情况下,可能需要使用提供的 WebSocketHandlerAdapter 服务来创建 WebSocketService bean,以便配置 WebSocket 服务器属性。 例如:spring-doc.cadn.net.cn

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

	@Override
	public WebSocketService getWebSocketService() {
		TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
		strategy.setMaxSessionIdleTimeout(0L);
		return new HandshakeWebSocketService(strategy);
	}
}
@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

	@Override
	fun webSocketService(): WebSocketService {
		val strategy = TomcatRequestUpgradeStrategy().apply {
			setMaxSessionIdleTimeout(0L)
		}
		return HandshakeWebSocketService(strategy)
	}
}

高级配置模式

@EnableWebFlux 导入 DelegatingWebFluxConfiguration,该配置会:spring-doc.cadn.net.cn

在高级模式下,您可以移除 @EnableWebFlux,并直接继承 DelegatingWebFluxConfiguration,而不是实现 WebFluxConfigurer,如下例所示:spring-doc.cadn.net.cn

@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {

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

	// ...
}

您可以保留 WebConfig 中的现有方法,但现在也可以覆盖基类中的 Bean 声明,同时类路径上仍然可以存在任意数量的其他 WebMvcConfigurer 实现。spring-doc.cadn.net.cn