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. Actually this is a common issue when I searched the solution. All the solutions are related to missing dependencies of Spring Boot starter spring-boot-starter-web.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:395) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at demo.MyApplicationKt.main(WorkerApplication.kt:12) [classes/: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.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:178) ~[spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:152) ~[spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE]
... 8 common frames omitted

But this is not the case for me. My project is created from start.spring.io and the basic project worked fine. It’s broken after I added some dependencies.

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. A quick search in the output of mvn dependency:tree points out that one of the newly-added library has a transitive dependency to spring-webmvc, so spring-webmvc is added to the CLASSPATH and Spring Boot treated the project as a servlet application.

1
2
3
4
5
6
7
8
9
10
11
12
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}

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.
1
2
3
4
5
6
7
8
@SpringBootApplication
class MyApplication

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