如何阻止Spring Boot自动配置Spring Web?

33

我正在使用 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
5个回答

37

参考:该用例已在Spring Boot 参考指南中记录:

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

application.properties:

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

5
非废弃版本现在为spring.main.web-environment-type=none。 - mliu
也许它们又改了,但现在是 spring.main.web-application-type - DerM

28

第一个技巧:

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 的自动配置而无需修改我的主启动方法,那将是很好的。 - membersound
虽然您的建议可行,谢谢!但无论如何,仅基于注释禁用自动配置会更好。 - membersound
7
spring.main.web_environment=false 更好... 不需要编写任何Java :-) - Artem Bilan
@membersound 今天我也遇到了同样的问题。最终我放弃了使用 RestTemplate,转用 Retrofit:http://square.github.io/retrofit/ … 首先,它从我的类路径中删除了 spring-web 依赖项。其次,它更容易理解和阅读。 - jamsesso

15

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

spring.main.web-application-type=none

这里是定义允许值的枚举。


1
然而,链接页面并没有提供有关 spring.main.web-application-type 属性的任何信息(在我撰写此文时),甚至没有说明有效值是什么。搜索 Spring WebApplicationType API 将显示有效值为 servletreactivenone(像这样小写,我猜)。 - ddekany
@ddekany 他们一定更改了文档。感谢你指出这一点! - geoand

14

这在Spring Boot 2.x中有效

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

3
我试图使用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/

I was building a new Spring WebFlux application with Spring Boot. After downloading the project template from start.spring.io, I added some third-party dependencies and tried to start the application. Then I met the error org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean....

The error message is the clue to the solution. It says Unable to start ServletWebServerApplicationContext, but my project is using WebFlux and it’s a reactive web project, not a servlet-based Spring Web MVC project.

Debugging into the Spring source code helped me find the cause. In the method deduceWebApplicationType of org.springframework.boot.SpringApplication, the web application type is set to WebApplicationType.REACTIVE only when classes of Spring Web MVC is not present in the CLASSPATH.

The solution is easy once the root cause is identified. We can either:

Update Maven dependencies to exclude spring-webmvc, or Set the web application type to WebApplicationType.REACTIVE explicitly, as shown below.

@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

看这里!问题解决了!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接