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:156)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at com.xx.XXApplication.main(XXApplication.java:11)
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:203)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:179)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:153)
... 8 common frames omitted
新加了个包,编译正常,启动出现错误,所以问题一定在我新加的包里(此处的包省略,假设为jj-xx),这个包里的jj-xx依赖有
[INFO] +- javax.servlet:javax.servlet-api:jar:4.0.1:compile
[INFO] +- javax.servlet.jsp:jsp-api:jar:2.2:compile
[INFO] +- org.eclipse.jetty:jetty-server:jar:9.4.20.v20190813:compile
[INFO] | +- org.eclipse.jetty:jetty-http:jar:9.4.20.v20190813:compile
[INFO] | | \- org.eclipse.jetty:jetty-util:jar:9.4.20.v20190813:compile
[INFO] | \- org.eclipse.jetty:jetty-io:jar:9.4.20.v20190813:compile
[INFO] +- org.codehaus.groovy:groovy-all:jar:2.4.13:compile
[INFO] +- org.apache.commons:commons-exec:jar:1.3:compile
[INFO] \- cglib:cglib:jar:2.1:compile
[INFO] +- asm:asm:jar:1.5.3:compile
[INFO] +- asm:asm-util:jar:1.3.4:compile
[INFO] \- aspectwerkz:aspectwerkz-core:jar:0.8.1:compile
另外因为一些上下文需要,之前还引入了spring-web相关的依赖(这里猜想可能是因为一些包的必要条件满足才导致程序启动为web程序
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>xxx</version>
</dependency>
如下是解决方式
根据报错提示,application启动的时候,根据webApplicationType判断的运行环境
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
继续往下看,webApplicationType是deduceFromClasspath生成的
this.webApplicationType = WebApplicationType.deduceFromClasspath();
最后是deduceFromClasspath方法里,返回servlet方法的逻辑,大概有三种情况
- 存在org.springframework.web.reactive.DispatcherHandler && 不存在org.springframework.web.servlet.DispatcherServlet && 不存在org.glassfish.jersey.servlet.ServletContainer,为REACTIVE程序
- SERVLET_INDICATOR_CLASSES字符串数组里有一个不存在时,为非web程序
- SERVLET_INDICATOR_CLASSES都存在时,为SERVLET环境
注: String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
return SERVLET;
}
}
综上所述,只存在spring-web时还是非web程序,当我引入依赖并引入其他有关javax.servlet.Servlet 时,就导致我的运行程序为SERVLET。
另外还提供另一种解决方式
外层配置里加上,这是创建 Environment
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableEnvironment 实例:
spring.main.web-application-type=none
#spring.main.web-application-type=servlet
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;//这里就是根据外层配置去获取的none类型
} else {
switch(this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
}
```