如果在 Spring Boot 中使用了 @EnableWebFlux,则无法从WebFlux分发静态资源

結論:
总之

如果在Spring Boot 2.3.4.RELEASE版本中使用Spring WebFlux时,使用@EnableWebFlux注解将无法分发静态资源。

概要

多年未曾开发WEB服务器,这次我决定使用信息十分丰富的Spring Boot,因为不仅Java是我久违的开发语言,WEB服务器也是。

暂时没有使用Java的时候,Spring Framework中添加了Spring WebFlux,所以我决定好好利用一下WebFlux。

在初次阅读完Spring WebFlux的文档后,我使用Spring Boot自动配置了应用程序。

在此阶段使用WebFlux并没有大问题,但后来需要分发静态资源。

如果在Spring Boot中配置了WebFlux,可以像Spring MVC一样分发静态资源。我原以为只要将资源放置在classpath:/static/中,并在Web浏览器中访问,服务器就会返回响应,但实际上返回的是404 Not Found。

我有些疑惑是否弄错了什么,于是查看了Spring Boot的文档,文档中确实写着可以实现。

在文档中提到的静态资源未被发布。
为了弄清原因,我查看了Spring Boot的WebFlux相关的自动配置。

我在寻找用于分发静态资源的WebFlux配置时,发现了WebFluxAutoConfiguration。

由于在WebFluxConfig类的addResourceHandlers方法中添加了静态资源的映射,所以在WebFluxConfig类的addResourceHandlers方法和WebFlux构造函数中添加了断点,并附加了调试器以启动应用程序。然而,即使应用程序已经启动完毕,断点仍未命中。

当Spring Boot的自动配置没有被调用时,通常是由于@Bean缺失或库缺失而导致自动配置条件无法满足的情况发生。

当我重新翻阅Spring Boot的文档时,我意识到我可能错过了什么,同时文档明确写明了原因。

因果

解释

由于

缘故

缘由

理由

起因

根源

Spring Boot使用WebFluxAutoConfiguration来配置WebFlux。
这个类上有@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })的注解,
如果已经有WebFluxConfigurationSupport的@Bean注册,那么这个自动配置就不会执行。

当检查@EnableWebFlux的定义时,我们可以看到它带有@Import(DelegatingWebFluxConfiguration.class)这个注解。
DelegatingWebFluxConfiguration是WebFluxConfigurationSupport的实现,因此,由Spring Boot提供的WebFluxAutoConfiguration不再通过ConditionalOnMissingBean起到自动配置的作用。

最初看Spring WebFlux的文档时,我看到@Configuration类上有@EnableWebFlux注解,所以我误以为实现WebFlux应用程序必须要添加这个注解。

然而,由于Spring Boot为了向WebFlux添加功能,提供了自己的WebFluxConfigurationSupport,因此在启用Spring Boot时,不能使用@EnableWebFlux注解的规则存在。

这一区域的规范在Spring Boot的文档中已经详细说明了,但由于在阅读了Spring WebFlux的文档之后,所以我不小心忽略了它。

闲话不多

Spring Boot会检测类路径上的库,并确定要将其配置为Spring MVC还是Spring WebFlux作为WEB服务器。

当存在Spring MVC和Spring WebFlux两个库时,如何控制启用的WEB服务器,我做了一些调查,发现可以通过Spring Boot属性spring.main.web-application-type指定为REACTIVE来配置WebFlux应用程序。

判断 spring.main.web-application-type 的设置状态是通过 WebFluxAutoConfiguration 上注解 @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) 来进行的。

如果想要使用Spring MVC,可以通过设置spring.main.web-application-type为SERVLET来实现。

广告
将在 10 秒后关闭
bannerAds