java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String when deploying to Tomcat in cargo
java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String when deploying to Tomcat in cargo
我在使用 maven-cargo-plugin 在嵌入式 Tomcat 7 上部署 Web 应用程序时遇到问题。我在 webapps pom 中创建了一个新的 maven 配置文件,它通过 maven-cargo-plugin 创建了一个 Tomcat 容器,然后通过 soapui-maven-plugin 执行了一个 soapui 测试用例。
webapp 连接到一些 IBM WebSphere MQ,因此我覆盖了一些容器配置文件:
- 将 MQ 作为资源添加到 server.xml 以进行 JNDI 查找
- 通过覆盖 web.xml
将我的自定义 applicationContext.xml 添加到类路径
- 在 context.xml 中添加了连接到 MQ 所需的资源
- 将本地安装的 IBM Websphere MQClient 的 lib 目录路径添加到容器 common.loader 以便容器可以使用其库
此外,我将所需的 websphere.mq.*.jar 文件和 j2ee-1.4.jar 从本地 WebsSphere Server 安装复制到 Tomcat 容器 lib 目录,方法是通过以下方式添加它们货物 <file>
标签。
现在,当我使用此命令启动 Maven 时(其中 runITs 激活创建的配置文件):
clean verify -U -Dhttps.protocols=TLSv1,SSLv3 -DrunITs -X
部署失败:
INFO] [talledLocalContainer] org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/cargocpc]]
[INFO] [talledLocalContainer] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
[INFO] [talledLocalContainer] at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
[INFO] [talledLocalContainer] at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
[INFO] [talledLocalContainer] at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1081)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1877)
[INFO] [talledLocalContainer] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
[INFO] [talledLocalContainer] at java.util.concurrent.FutureTask.run(FutureTask.java:262)
[INFO] [talledLocalContainer] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
[INFO] [talledLocalContainer] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
[INFO] [talledLocalContainer] at java.lang.Thread.run(Thread.java:745)
[INFO] [talledLocalContainer] Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.getClassLoader()Ljava/lang/ClassLoader;
[INFO] [talledLocalContainer] at org.apache.catalina.startup.WebappServiceLoader.load(WebappServiceLoader.java:90)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.ContextConfig.processServletContainerInitializers(ContextConfig.java:1577)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1281)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:889)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:386)
[INFO] [talledLocalContainer] at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
[INFO] [talledLocalContainer] at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
[INFO] [talledLocalContainer] at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5412)
[INFO] [talledLocalContainer] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
[INFO] [talledLocalContainer] ... 10 more
我已经尝试寻找可能的解决方案,f. e.尝试了此处提供的解决方案:java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String;
但我可以排除可能的原因,因为:
- 我的容器是 Tomcat 7,因此支持 Servlet API 2.5
- web.xml 符合 Servlet API 2.5
WEB-INF/lib
或 JRE/lib
中没有 j2ee.jar 或 servlet-api.jar 文件
确保我的设置符合这三点后,我仍然得到上述错误。
有谁知道还有什么可能导致这种情况?
似乎 Tomcat 试图调用此方法,该方法仅存在于 servlet-api-3.0 或更高版本中。由于我无法确切地弄清楚容器从哪里得到这种错误的依赖关系,所以我使用不同的方法解决了我的问题。
我没有通过 maven-cargo-plugin 创建基本的 Tomcat 并覆盖配置文件,而是复制了一个已经工作的本地配置并通过添加
告诉 cargo 使用此配置
<configuration>
<type>existing</type>
<home>C:\path\to\tomcat\home</home>
</configuration>
到插件配置
问题的第一个答案将构建绑定到本地计算机上的具体设置。人们也许能够在构建服务器上复制它,但它会很笨拙且容易出错。我个人更喜欢配置构建,这样它就可以在没有任何外部依赖的情况下工作。当我们需要 运行 数据库迁移或者当我们想测试 RabbitMQ 并且没有可用的嵌入式代理但至少应用程序 运行 是独立的时,我也不得不妥协。
因此,如果我是你,我会更深入地研究并进行配置,以便能够在没有这样的本地文件夹的情况下处理你的用例。由于缺少信息(您的货物配置),我无法为您提供有效的答案。但我会向您指出 org.apache.tomcat.maven.tomcat7-maven-plugin
。它对我们非常有效。我在另一个项目中使用了 Cargo,我发现 tomcat7 插件更容易使用。
您可以提供自己的server.xml
:Run Tomcat and deploy project with own server.xml
您可以在 <dependencies>
部分指定 (add/override) 依赖项 - 这应该可以解决您的 servlet-api 版本问题。
您可以通过将它们添加为 jar 中的依赖项来添加自定义配置(比如我们放入 lib 文件夹中的一些属性文件,以便将它们放在类路径中)。
这是嵌入 Tomcat up 和 运行ning 的一种非常通用且简单的方法。希望能帮到你。
也许可以给你一些关于 tomcat7 插件配置的入门知识:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>tomcat-run</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run-war-only</goal>
</goals>
<configuration>
<webapps>
<webapp>
<groupId>${project.groupId}</groupId>
<artifactId>project-web</artifactId>
<version>${project.version}</version>
<type>war</type>
<asWebapp>true</asWebapp>
<contextPath>/project-path</contextPath>
</webapp>
</webapps>
<protocol>org.apache.coyote.http11.Http11NioProtocol</protocol>
<port>${app.port}</port>
<fork>true</fork>
</configuration>
</execution>
<execution>
<id>tomcat-shutdown</id>
<phase>post-integration-test</phase>
<goals>
<goal>shutdown</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>project-test-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<classifier>runtime</classifier>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
上面稍微解释一下。我们使用 JaCoCo 收集 Sonar 的集成测试覆盖率。我们需要一个特定的 Tomcat 版本(以测试它是否适用于操作提供的版本)并且我们已经通过 <port>
和 <protocol>
指令直接覆盖了一些 server.xml 配置。
我在使用 maven-cargo-plugin 在嵌入式 Tomcat 7 上部署 Web 应用程序时遇到问题。我在 webapps pom 中创建了一个新的 maven 配置文件,它通过 maven-cargo-plugin 创建了一个 Tomcat 容器,然后通过 soapui-maven-plugin 执行了一个 soapui 测试用例。
webapp 连接到一些 IBM WebSphere MQ,因此我覆盖了一些容器配置文件:
- 将 MQ 作为资源添加到 server.xml 以进行 JNDI 查找
- 通过覆盖 web.xml 将我的自定义 applicationContext.xml 添加到类路径
- 在 context.xml 中添加了连接到 MQ 所需的资源
- 将本地安装的 IBM Websphere MQClient 的 lib 目录路径添加到容器 common.loader 以便容器可以使用其库
此外,我将所需的 websphere.mq.*.jar 文件和 j2ee-1.4.jar 从本地 WebsSphere Server 安装复制到 Tomcat 容器 lib 目录,方法是通过以下方式添加它们货物 <file>
标签。
现在,当我使用此命令启动 Maven 时(其中 runITs 激活创建的配置文件):
clean verify -U -Dhttps.protocols=TLSv1,SSLv3 -DrunITs -X
部署失败:
INFO] [talledLocalContainer] org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/cargocpc]]
[INFO] [talledLocalContainer] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
[INFO] [talledLocalContainer] at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
[INFO] [talledLocalContainer] at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
[INFO] [talledLocalContainer] at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1081)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1877)
[INFO] [talledLocalContainer] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
[INFO] [talledLocalContainer] at java.util.concurrent.FutureTask.run(FutureTask.java:262)
[INFO] [talledLocalContainer] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
[INFO] [talledLocalContainer] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
[INFO] [talledLocalContainer] at java.lang.Thread.run(Thread.java:745)
[INFO] [talledLocalContainer] Caused by: java.lang.NoSuchMethodError: javax.servlet.ServletContext.getClassLoader()Ljava/lang/ClassLoader;
[INFO] [talledLocalContainer] at org.apache.catalina.startup.WebappServiceLoader.load(WebappServiceLoader.java:90)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.ContextConfig.processServletContainerInitializers(ContextConfig.java:1577)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1281)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:889)
[INFO] [talledLocalContainer] at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:386)
[INFO] [talledLocalContainer] at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
[INFO] [talledLocalContainer] at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
[INFO] [talledLocalContainer] at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5412)
[INFO] [talledLocalContainer] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
[INFO] [talledLocalContainer] ... 10 more
我已经尝试寻找可能的解决方案,f. e.尝试了此处提供的解决方案:java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String;
但我可以排除可能的原因,因为:
- 我的容器是 Tomcat 7,因此支持 Servlet API 2.5
- web.xml 符合 Servlet API 2.5
WEB-INF/lib
或JRE/lib
中没有 j2ee.jar 或 servlet-api.jar 文件
确保我的设置符合这三点后,我仍然得到上述错误。
有谁知道还有什么可能导致这种情况?
似乎 Tomcat 试图调用此方法,该方法仅存在于 servlet-api-3.0 或更高版本中。由于我无法确切地弄清楚容器从哪里得到这种错误的依赖关系,所以我使用不同的方法解决了我的问题。
我没有通过 maven-cargo-plugin 创建基本的 Tomcat 并覆盖配置文件,而是复制了一个已经工作的本地配置并通过添加
告诉 cargo 使用此配置<configuration>
<type>existing</type>
<home>C:\path\to\tomcat\home</home>
</configuration>
到插件配置
问题的第一个答案将构建绑定到本地计算机上的具体设置。人们也许能够在构建服务器上复制它,但它会很笨拙且容易出错。我个人更喜欢配置构建,这样它就可以在没有任何外部依赖的情况下工作。当我们需要 运行 数据库迁移或者当我们想测试 RabbitMQ 并且没有可用的嵌入式代理但至少应用程序 运行 是独立的时,我也不得不妥协。
因此,如果我是你,我会更深入地研究并进行配置,以便能够在没有这样的本地文件夹的情况下处理你的用例。由于缺少信息(您的货物配置),我无法为您提供有效的答案。但我会向您指出 org.apache.tomcat.maven.tomcat7-maven-plugin
。它对我们非常有效。我在另一个项目中使用了 Cargo,我发现 tomcat7 插件更容易使用。
您可以提供自己的server.xml
:Run Tomcat and deploy project with own server.xml
您可以在 <dependencies>
部分指定 (add/override) 依赖项 - 这应该可以解决您的 servlet-api 版本问题。
您可以通过将它们添加为 jar 中的依赖项来添加自定义配置(比如我们放入 lib 文件夹中的一些属性文件,以便将它们放在类路径中)。
这是嵌入 Tomcat up 和 运行ning 的一种非常通用且简单的方法。希望能帮到你。
也许可以给你一些关于 tomcat7 插件配置的入门知识:
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>tomcat-run</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run-war-only</goal>
</goals>
<configuration>
<webapps>
<webapp>
<groupId>${project.groupId}</groupId>
<artifactId>project-web</artifactId>
<version>${project.version}</version>
<type>war</type>
<asWebapp>true</asWebapp>
<contextPath>/project-path</contextPath>
</webapp>
</webapps>
<protocol>org.apache.coyote.http11.Http11NioProtocol</protocol>
<port>${app.port}</port>
<fork>true</fork>
</configuration>
</execution>
<execution>
<id>tomcat-shutdown</id>
<phase>post-integration-test</phase>
<goals>
<goal>shutdown</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>project-test-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<classifier>runtime</classifier>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
上面稍微解释一下。我们使用 JaCoCo 收集 Sonar 的集成测试覆盖率。我们需要一个特定的 Tomcat 版本(以测试它是否适用于操作提供的版本)并且我们已经通过 <port>
和 <protocol>
指令直接覆盖了一些 server.xml 配置。