Получение NoSuchMethodError: javax.servlet.ServletContext.addServlet в Spring Boot при запуске приложения Spring MVC
Я получаю исключение ниже, когда я пытаюсь запустить приложение Spring MVC, используя Spring boot...
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
16 ответов
Если вы хотите узнать, откуда загружается класс, попробуйте
java -verbose:class -jar foo.jar | grep javax.servlet.ServletContext
где foo.jar
это толстый JAR, произведенный Gradle или Maven. Например, ServletContext
класс может быть прочитан от старшего servlet-api
JAR в каталоге расширений JDK вместо ваших зависимостей 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!/]
Я решил это за исключением транзитивной зависимости 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>
Gradle решение.
У меня была похожая проблема в моем lib jar, которая по какой-то причине принесла старую версию javax.servlet.ServletContext, которая позже была загружена моим подпружиненным загрузочным модулем вместо собственного предоставленного класса, что вызвало NoSuchMethodError
Я исправил это, отредактировав build.gradle моего модуля lib:
configurations {
provided.all*.exclude group: 'javax.servlet'
}
Для тех, кто не может решить эту проблему, исключив servlet-api
Вот альтернатива:
По умолчанию Spring Boot оказывается Tomcat 8. Если вы работаете с другой версией Tomcat и хотите исправить эту ошибку, просто добавьте версию tomcat в свойства pom:
<properties>
<tomcat.version>7.0.63</tomcat.version>
</properties>
У меня это было в весеннем загрузочном веб-приложении, только на сервере развертывания (работало нормально на моей локальной машине). Я решаю это, добавив:
<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
У меня была эта проблема при попытке запустить мой весенний загрузочный сервер во время тестов (используя gradle + spock). Я проследил проблему до библиотеки Wiremock.
Это исправило это:
testCompile('com.github.tomakehurst:wiremock:1.58') {
exclude module: 'servlet-api' // this exclude fixed it
}
FYI
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
банка содержит версию ServletContext
это несовместимо с версией 1.3.2 пружинной загрузки (работало нормально, по крайней мере, до 1.2.6).
Я использовал Gradle и что сработало для меня:
configurations {
all*.exclude group: '', module: 'servlet-api'
}
Он обрезал дерево зависимостей по желанию.
Я работал с Hadoop 2.7.2 с использованием Spring-boot, в следующих зависимостях 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>
Согласно этому решению: https://stevewall123.wordpress.com/2015/04/17/spring-boot-application-and-tomcat-error-a-child-container-failed-during-start/
Вы можете изменить версию Tomcat, установив свойство "tomcat.version":
ext['tomcat.version'] = '7.0.63' //my version of Tomcat
dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
}
это работает для меня, благодаря автору этой статьи.
Ура:)
Я не мог отследить проблемную ссылку, за исключением того, что знал, что она каким-то образом попадает в мой путь к классам, поэтому вот мои 2 цента для ленивых разработчиков, использующих eclipse:
Прокрутите список зависимостей maven в дереве проекта (обычно в разделе Ресурсы Java -> Библиотеки -> Зависимости Maven), отследите проблемный добавленный jar, который вы хотите исключить из упакованного JAR-файла, щелкните правой кнопкой мыши по нему -> выберите Maven -> Exclude Maven Артефакт! Вуаля - автоматически исключение будет добавлено к вашей поме прямо под зависимостью, которая ссылается на него.
Мой 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>
Удачи!
Я использую Jetty в моем проекте и получил ту же ошибку. Моим быстрым решением было исключить встроенный Tomcat из зависимости Maven:
<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>
Если вы используете STS и добавили библиотеку Groovy в свой проект (Свойства проекта -> Путь сборки Java -> Библиотеки), убедитесь, что вы выбрали опцию "Нет, только groovy-all". Другой вариант "Да, включая groovy-all и bsf.jar..., servlet-2.4.jar" добавляет servlet-2.4.jar, который конфликтует со встроенными классами tomcat8, что приводит к этой проблеме.
mvn dependency:tree
не раскрыл servlet-api.jar
на моем пути к классам, но щелкнув правой кнопкой мыши по проекту (в Eclipse) и перейдя в Build Path / Configure Build Path, я обнаружил, что в моем JREK 1.7.0_51 в рабочей области по умолчанию эта банка была jre/lib/ext
каталог (по крайней мере, в моей установке). Я попытался и не смог удалить его из моего classpath. @ Решение Педро по принуждению версии Tomcat к 7 сработало. Так же была установлена последняя версия Java 7: JDK 1.7.0_79.
Я тоже сталкивался с этой ошибкой. У меня есть проект 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;
просто переместив orderEntry для Java EE вниз, ошибка исчезнет, и я смогу скомпилировать еще раз.
Для меня это было решением;
https://mkyong.com/java/servlet-api-2-5-jar-jar-not-loaded/
добавление зависимости servlet-api к pom.xml
Для быстрого решения я удалил servlet-api.jar вручную из lib и затем собрал приложение, и оно работает. Хотя, в идеале, как рекомендует Kumetix, нужно тщательно изучить до зависимости, которая заставляет его загружаться в classpath.