gateway网关启动报错
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
找不到bean服务
看网上很多教程说是因为缺少web依赖,但是发现依赖的父依赖中都包含了
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
所以解决办法是排除父依赖中的如上两个依赖
<dependency> <groupId>com.XX.project</groupId> <artifactId>parent</artifactId> <version>2.0.4-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </exclusion> </exclusions> </dependency>
但是启动的时候发现还是报错
所以加上spring-boot-web的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
之后发现又报另外一个错误
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-09-17 16:53:20.207 ERROR 2752 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway.
Action:
Please set spring.main.web-application-type=reactive or remove spring-boot-starter-web dependency.
二、问题分析
从报错内容上来看是找不到ServletWebServerFactory这个bean导致的错误。从Spring Framework 5.0开始,引入的新的响应式Web框架(Spring WebFlux),与Spring MVC不同,它不需要Servlet API,完全异步和非阻塞。Spring Cloud Gateway 运用了响应式编程(WebFlux),因此它需要依赖于Servlet API,但是启动的时候为什么还是去找Servlet呢?百思不得其解。
按照报错信息在yml中spring: main: web-application-type: reactive就成功了
spring:
main:
web-application-type: reactive
划重点:
1.在pom文件中引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
2.在yml文件中加上
spring: main: web-application-type: reactive
知识点:
WebApplicationType 的三种启动方式的描述
我们一般采用的是SERVLET。
public enum WebApplicationType {
/**
* 不启动内嵌的WebServer,不是运行web application
*/
NONE,
/**
* 启动内嵌的基于servlet的web server
*/
SERVLET,
/**
* 启动内嵌的reactive web server,这个application是一个reactive web application
*/
REACTIVE;
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
static WebApplicationType deduceFromClasspath() {
// 尝试加载org.springframework.web.reactive.DispatcherHandler,如果成功并且加载org.springframework.web.servlet.DispatcherServlet和org.glassfish.jersey.servlet.ServletContainer失败,则这个application是WebApplicationType.REACTIVE类型。
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
// 如果ClassLoader里面同时加载这两个 javax.servlet.Servlet和 org.springframework.web.context.ConfigurableWebApplicationContext成功。则application是WebApplicationType.NONE 类型。
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// application是 WebApplicationType.SERVLET 类型。
return WebApplicationType.SERVLET;
}
static WebApplicationType deduceFromApplicationContext(Class<?> applicationContextClass) {
if (isAssignable(SERVLET_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
return WebApplicationType.SERVLET;
}
if (isAssignable(REACTIVE_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
return WebApplicationType.REACTIVE;
}
return WebApplicationType.NONE;
}
-
WebApplicationType.REACTIVE classpath下存在org.springframework.web.reactive.DispatcherHandler
-
WebApplicationType.SERVLET classpath下存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext
-
WebApplicationType.NONE 不满足以上条件。
推荐看一下这篇博客
彻底找到Spring Webflux与WebMVC 冲突原因_努力码农的博客-CSDN博客_webflux和webmvc共存