如何防止spring-web的spring-boot自动配置?

Posted

技术标签:

【中文标题】如何防止spring-web的spring-boot自动配置?【英文标题】:How to prevent spring-boot autoconfiguration for spring-web? 【发布时间】:2015-06-30 06:56:26 【问题描述】:

我正在使用 spring-boot 并在 maven pom 中添加了 spring-web 依赖项,以使用 RestTemplate

现在 spring 尝试初始化一个EmbeddedServletContext。如何预防?

Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:133)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:474)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:183)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:156)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:130)
    ... 8 more

【问题讨论】:

【参考方案1】:

我尝试使用 Spring Boot 2.06 构建响应式 Web 应用程序并收到此错误:

org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:155) ~[spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) ~[spring-context-5.0.10.RELEASE.jar:5.0.10.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1242) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1230) [spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at com.vogella.springboot2.Test3Application.main(Test3Application.java:10) [main/:na]
Caused by: org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory(ServletWebServerApplicationContext.java:204) ~[spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:178) ~[spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:152) ~[spring-boot-2.0.6.RELEASE.jar:2.0.6.RELEASE]
    ... 8 common frames omitted

此链接解释了问题,并提供了两个建议:

https://vividcode.io/Fixing-Spring-Boot-error-Unable-to-start-ServletWebServerApplicationContext-due-to-missing-ServletWebServerFactory-bean/

我正在使用 Spring Boot 构建一个新的 Spring WebFlux 应用程序。 从 start.spring.io 下载项目模板后,我添加了 一些第三方依赖项并尝试启动应用程序。然后 我遇到了错误 org.springframework.context.ApplicationContextException:无法 由于缺少启动 ServletWebServerApplicationContext ServletWebServerFactory bean....

错误信息是解决问题的线索。它说无法启动 ServletWebServerApplicationContext,但我的项目使用的是 WebFlux 它是一个响应式 Web 项目,而不是基于 servlet 的 Spring Web MVC 项目。

调试 Spring 源代码帮助我找到了原因。在里面 方法 deuceWebApplicationType 的 org.springframework.boot.SpringApplication,web应用类型 仅当 Spring Web 的类时才设置为 WebApplicationType.REACTIVE CLASSPATH 中不存在 MVC。

一旦确定了根本原因,解决方案就很容易了。我们可以:

更新Maven依赖排除spring-webmvc,或者设置web 将应用程序类型显式设置为 WebApplicationType.REACTIVE,如图所示 下面。

@SpringBootApplication class MyApplication
fun main(args: Array<String>) 
    val app = SpringApplication(MyApplication::class.java)
    app.webApplicationType = WebApplicationType.REACTIVE
    app.run(*args)

不幸的是,这些解决方案都不适合我。相反,我调整了 geoand 的回复,并将其添加到我的application.properties

spring.main.web-application-type=reactive

瞧!问题已解决!

【讨论】:

【参考方案2】:

这适用于 Spring Boot 2.x

public static void main(String[] args) 
   new SpringApplicationBuilder(MyApplication.class)
            .web(WebApplicationType.NONE)
            .build()
            .run(args);

【讨论】:

【参考方案3】:

虽然禁用 Web 环境的旧方法(如 @Tim 的回答中所述)在 Spring Boot 2.x 中仍然有效,但新的首选方法是设置以下属性

spring.main.web-application-type=none

Here 是定义允许值的枚举

【讨论】:

链接页面没有提供有关 spring.main.web-application-type 属性的任何信息(当我写这篇文章时),甚至没有提供有效值是什么。谷歌搜索Spring WebApplicationType API 将显示有效值为servletreactivenone(我猜是小写的)。 @ddekany 他们一定更改了文档。感谢您指出这一点!【参考方案4】:

供参考:此用例记录在Spring Boot Reference Guide:

并非所有 Spring 应用程序都必须是 Web 应用程序(或 Web 服务)。如果您想在 main 方法中执行一些代码,同时还要引导一个 Spring 应用程序来设置要使用的基础设施,那么使用 Spring Boot 的 SpringApplication 功能很容易。 SpringApplication 更改其 ApplicationContext 类取决于它是否认为需要 Web 应用程序。您可以做的第一件事就是将 servlet API 依赖项从类路径中移除。如果您不能这样做(例如,您从同一代码库运行 2 个应用程序),那么您可以显式调用 SpringApplication.setWebEnvironment(false),或设置 applicationContextClass 属性(通过 Java API 或使用外部属性)。您希望作为业务逻辑运行的应用程序代码可以实现为 CommandLineRunner,并作为 @Bean 定义放入上下文中。

application.properties:

spring.main.web-environment=false   #webEnvironment property

【讨论】:

非弃用版本现在是 spring.main.web-environment-type=none 也许他们又改了,但现在是spring.main.web-application-type【参考方案5】:

第一招:

public static void main(String[] args) throws Exception 
    ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class)
                .web(false)
                .run(args);

第二:

@Configuration
@EnableAutoConfiguration(exclude = WebMvcAutoConfiguration.class)
public class Application 

【讨论】:

我尝试了@EnableAutoConfiguration(exclude = WebMvcAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class),但仍然出现同样的错误...如果spring-web 的自动配置可以通过注释禁用,而无需修改我的主要启动方法,那就太好了...跨度> 虽然您的建议有效,但谢谢!但无论如何,只禁用基于自动配置注释会很好。 spring.main.web_environment=false 更好不过...无需编写任何 Java 代码 :-) @membersound 我今天遇到了同样的问题。我最终放弃了 RestTemplate 进行改造:square.github.io/retrofit ... 一方面,它摆脱了我的类路径中的 spring-web 依赖。对于两个人来说,推理和阅读要容易得多。

以上是关于如何防止spring-web的spring-boot自动配置?的主要内容,如果未能解决你的问题,请参考以下文章

项目导入时没有spring-web 包

Spring-web源码解析之ContentNegotiationStrategy

试图加快spring-web端点json序列化(加力)

spring-web中的StringHttpMessageConverter简介

spring-web.xml 模板

spring-web中的WebDataBinder理解