在运行 Spring MVC 应用程序时在 Spring Boot 中获取 NoSuchMethodError: javax.servlet.ServletContext.addServlet
Posted
技术标签:
【中文标题】在运行 Spring MVC 应用程序时在 Spring Boot 中获取 NoSuchMethodError: javax.servlet.ServletContext.addServlet【英文标题】:Getting NoSuchMethodError: javax.servlet.ServletContext.addServlet in Spring Boot while running a Spring MVC application 【发布时间】:2014-07-27 15:32:47 【问题描述】:当我尝试使用 Spring Boot 运行 Spring MVC 应用程序时遇到异常...
ContainerBase: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[]]
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:799)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
... 6 more
Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.addServlet(Ljava/lang/String;Ljavax/servlet/Servlet;)Ljavax/servlet/ServletRegistration$Dynamic;
at org.springframework.boot.context.embedded.ServletRegistrationBean.onStartup(ServletRegistrationBean.java:166)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext$1.onStartup(EmbeddedWebApplicationContext.java:214)
at org.springframework.boot.context.embedded.tomcat.ServletContextInitializerLifecycleListener.lifecycleEvent(ServletContextInitializerLifecycleListener.java:54)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5355)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 6 more
【问题讨论】:
你能发一下代码sn-p吗? 你使用什么依赖? 检查您的 Web 服务器支持的 servlet 版本,以及您在应用程序中实现的 servlet 版本(可以在 web.xml 中找到)。方法addServlet()
仅在 servlet 3.0 中受支持。
看起来您的类路径上有旧版本的 tomcat 或 servlet API。使用其中一种可用工具来查看您的类路径(mvn 依赖项:树、gradle 依赖项等)。
是的,我可以在我的类路径中看到 servlet Api 2.5,但我没有在我的 pom 中提到任何这样的依赖项。那么这怎么会出现在我的类路径中,如何确保 servlet api我的项目中使用的是3.0
【参考方案1】:
我解决了它,不包括传递 servlet-api 依赖项。
在我的例子中,它是 com.github.isrsal:spring-mvc-logger
<dependency>
<groupId>com.github.isrsal</groupId>
<artifactId>spring-mvc-logger</artifactId>
<version>0.2</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
【讨论】:
我遇到了同样的问题,对我来说 servlet 2.3 依赖来自 telnetd-x:2.1.1 作为 spring-boot-starter-web artifact-id 的一部分。 谢谢!我有同样的问题,只是它发生在我正在生产的罐子里。所以,我更喜欢从我的工件附带的依赖项中排除一次javax.servlet
,而不是手动将它从依赖它的所有其他模块中排除。你有没有找到解决办法?
@kumetix 在 Maven 中有一个技巧:使用版本字符串 0.99-do-not-include 创建您自己的工件 javax.serlet:servlet-api。并在 google-cloud
依赖项中排除 javax.servlet
依赖项来解决它【参考方案2】:
如果你想知道类是从哪里加载的,试试
java -verbose:class -jar foo.jar | grep javax.servlet.ServletContext
其中foo.jar
是 Gradle 或 Maven 生成的胖 JAR。例如,ServletContext
类可能是从 JDK 扩展目录中较旧的 servlet-api
JAR 中读取的,而不是您的 Maven 或 Gradle 依赖项。
命令的输出看起来像这样......
$ java -verbose:class -jar build/libs/foo-0.2.3.jar | grep javax.servlet.ServletContext
[Loaded javax.servlet.ServletContext from jar:file:.../build/libs/foo-0.2.3.jar!/lib/javax.servlet-api-3.1.0.jar!/]
[Loaded javax.servlet.ServletContextListener from jar:file:.../build/libs/foo-0.2.3.jar!/lib/javax.servlet-api-3.1.0.jar!/]
[Loaded javax.servlet.ServletContextAttributeListener from jar:file:.../build/libs/foo-0.2.3.jar!/lib/javax.servlet-api-3.1.0.jar!/]
【讨论】:
我更喜欢这个答案,因为它能让你找到问题的根源。所有其他的都是“我也有这个,我通过......解决了它”。因此,如果您由于不同的原因而遇到相同的问题,则无法使用其他答案进行故障排除。这是最有用的全方位答案。mvn dependency:tree | grep servlet-api
【参考方案3】:
gradle 解决方案。
我在我的 lib jar 中遇到了类似的问题,由于某种原因,它带来了一个旧版本的 javax.servlet.ServletContext,它后来由我的 spring-boot 模块而不是它自己提供的类加载,从而导致 NoSuchMethodError
我通过编辑我的 lib 模块的 build.gradle 来修复它:
configurations
provided.all*.exclude group: 'javax.servlet'
【讨论】:
【参考方案4】:我使用的是 Gradle,什么对我有用:
configurations
all*.exclude group: '', module: 'servlet-api'
它以所需的方式修剪依赖树。
【讨论】:
谢谢,它帮助解决了我的问题。最后我搜索了使用gradle dependencies
引入'servlet-api'的依赖项,然后我使用了标准的gradle排除方法【参考方案5】:
我在 spring-boot webapp 中有这个,只在部署服务器中(在我的本地机器上运行良好)。我通过添加来解决它:
<dependencies>
<!-- … -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- … -->
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html
【讨论】:
【参考方案6】:对于无法通过排除 servlet-api
来解决问题的其他人,这里有一个替代方案:
事实证明 Spring Boot 默认使用 Tomcat 8。如果您正在运行不同版本的 Tomcat 并希望修复此错误,只需将您的 tomcat 版本添加到 pom 属性:
<properties>
<tomcat.version>7.0.63</tomcat.version>
</properties>
【讨论】:
在 STS 3.7.2 上尝试运行 Spring 安全和 Angular 教程 (spring.io/guides/tutorials/spring-security-and-angular-js) 中的基本项目 (github.com/spring-guides/tut-spring-security-and-angular-js/…) 后,这是唯一对我有用的解决方案.使用 mvn spring-boot:run 运行良好,但不能通过 IDE 使用 tomcat 8。【参考方案7】:为了快速解决问题,我已经从 lib 中手动删除了 servlet-api.jar,然后构建了应用程序并且它可以工作。不过,理想情况下,正如 Kumetix 所建议的那样,应该仔细检查导致它加载的依赖项在类路径中。
【讨论】:
【参考方案8】:mvn dependency:tree
没有在我的类路径上显示servlet-api.jar
,而是右键单击项目(在 Eclipse 中)并转到 Build Path / Configure Build Path显示我的默认工作区 JRE,JDK 1.7.0_51,在其 jre/lib/ext
目录中有那个 jar(至少在我的安装中)。我尝试将其从我的类路径中删除,但未能成功。 @Pedro 的 solution 将 tomcat 版本强制为 7 有效。安装最新版本的 Java 7:JDK 1.7.0_79 也是如此。
【讨论】:
【参考方案9】:在测试(使用 gradle + spock)期间尝试启动我的 Spring Boot 服务器时遇到了这个问题。我将问题追溯到wiremock库。
这解决了它:
testCompile('com.github.tomakehurst:wiremock:1.58')
exclude module: 'servlet-api' // this exclude fixed it
仅供参考
gradle dependencies
显示(删节):
\--- com.github.tomakehurst:wiremock:1.58
+--- org.mortbay.jetty:jetty:6.1.26
+--- org.mortbay.jetty:jetty-util:6.1.26
\--- org.mortbay.jetty:servlet-api:2.5-20081211
古老的 (2008) org.mortbay.jetty:servlet-api
jar 包含与 Spring Boot 1.3.2 版本不兼容的 ServletContext
版本(至少在 1.2.6 之前可以正常工作)。
【讨论】:
【参考方案10】:如果您使用 STS 并且已将 Groovy 库添加到您的项目(项目属性 -> Java 构建路径 -> 库),请确保选择“否,仅包含 groovy-all”选项。 “Yes, include groovy-all and bsf.jar ..., servlet-2.4.jar”的另一个选项添加了 servlet-2.4.jar,它与嵌入式 tomcat8 类冲突,导致此问题。
【讨论】:
这也是发生在我身上的事!【参考方案11】:我也遇到了这个错误。我有一个 Maven/Spring MVC/Spring Boot 项目。我使用 IntelliJ 作为 IDE,每当我向 POM.xml 添加新的依赖项时,IDE 都会更改 .iml 文件(如预期的那样),但奇怪的是它将以下行移至文件顶部:
<orderEntry type="library" name="Java EE 6-Java EE 6" level="project" />
一旦发生这种情况,我的项目将无法编译,并且出现同样的错误:
java.lang.NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String;
只需将 Java EE 的 orderEntry 移回底部,错误就会消失,我可以再次编译。
【讨论】:
【参考方案12】:我在我的项目中使用了 Jetty,但遇到了同样的错误。我的快速解决方案是从 Maven 依赖项中排除嵌入式 Tomcat:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-ws</artifactId>
<version>1.2.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
【讨论】:
【参考方案13】:根据这个解决方案: https://stevewall123.wordpress.com/2015/04/17/spring-boot-application-and-tomcat-error-a-child-container-failed-during-start/
您可以通过设置“tomcat.version”属性来更改Tomcat版本:
ext['tomcat.version'] = '7.0.63' //my version of Tomcat
dependencies
compile 'org.springframework.boot:spring-boot-starter-web'
感谢那篇文章的作者,它对我有用。
干杯:)
【讨论】:
【参考方案14】:我使用 Spring-boot 运行 Hadoop 2.7.2,以下 Hadoop 依赖项使用 javax.servlet,这会阻止嵌入式 tomcat 版本启动。我的 POM 中的以下排除项解决了问题。
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.2</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-hadoop-boot</artifactId>
<version>2.3.0.RELEASE-hadoop26</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.2</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
【讨论】:
【参考方案15】:除了知道它以某种方式进入我的类路径之外,我无法找到有问题的参考,所以这是我为使用 eclipse 的懒惰开发人员提供的 2 美分:
向下滚动项目树下的 maven 依赖项列表(通常在 Java 资源 -> 库 -> Maven 依赖项下),跟踪您希望从打包的 JAR 中排除的有问题的添加 jar,右键单击它 -> 选择 Maven -> 排除 Maven 工件! 瞧——会自动将排除项添加到您的 pom 中,就在引用它的依赖项下。
我的 BTW 是 jcifs...
<dependency>
<groupId>org.codelibs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.18.2</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
祝你好运!
【讨论】:
以上是关于在运行 Spring MVC 应用程序时在 Spring Boot 中获取 NoSuchMethodError: javax.servlet.ServletContext.addServlet的主要内容,如果未能解决你的问题,请参考以下文章
使用spring mvc在按钮单击时在表上添加行并将添加的行绑定到modelAttribute
使用 STOMP/WebSockets/Spring 从 @SubscribeMapping 返回原始字符串
如何在spring mvc 3.0中的同一jsp中显示运行时错误消息或sql错误消息