【问题标题】:Getting NoSuchMethodError: javax.servlet.ServletContext.addServlet in Spring Boot while running a Spring MVC application在运行 Spring MVC 应用程序时在 Spring Boot 中获取 NoSuchMethodError: javax.servlet.ServletContext.addServlet
【发布时间】: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

标签: java spring-mvc spring-boot nosuchmethoderror lifecycleexception


【解决方案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> 
      

      【讨论】:

      【解决方案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>
                    

                    祝你好运!

                    【讨论】:

                      猜你喜欢
                      • 2023-03-16
                      • 1970-01-01
                      • 2014-08-22
                      • 2017-01-04
                      • 2021-04-19
                      • 1970-01-01
                      • 2019-10-14
                      • 2018-05-13
                      • 2015-04-18
                      相关资源
                      最近更新 更多