如何从命令行在 WAR 中运行类?

How do I run a class in a WAR from the command line?

提问人:Simon 提问时间:12/4/2009 更新时间:10/20/2023 访问量:262922

问:

我有一个 Java 类,它有一个 main,我曾经从命令行作为独立应用程序运行,例如

java -jar myjar.jar params

我需要重新打包代码以在 apache 下运行,我的所有代码,包括旧 jar 中的入口点类,都已最终放入 WAR 文件中,以便轻松进入 Web 服务器。

但是,我仍然希望能够从命令行运行它,并且代码没有更改并且全部在那里,我只是不知道如何让它运行。

这是我尝试过的......

我以为 WAR 就像一个罐子,所以

java -jar mywar.war params

这失败了,因为清单中没有定义主类。

我手动将清单添加到战争中,然后再次尝试,效果相同。

我注意到在我的战争中,我有一个名为 META-INF 的文件夹,其中包含一个 manifest.mf,所以我添加了一行,声明我的主类,就像我声明普通清单一样......

Manifest-Version: 1.0
Main-Class: mypackage.MyEntryPointClass

这给出了一个 ,这是一种进步。这让我相信这只是一个路径问题,所以我尝试了noClassDefFoundError mypackage.MyEntryPointClass

Manifest-Version: 1.0
Main-Class: WEB-INF.classes.mypackage.MyEntryPointClass

我现在收到相同的错误,但带有堆栈跟踪......

Exception in thread "main" java.lang.NoClassDefFoundError: WEB-INF/classes/mypackage/MyEntryPointClass (wrong name: mypackage/MyEntryPointClass)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$100(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClassInternal(Unknown Source)

我已经用谷歌搜索了一会儿,但找不到任何可以回答我的问题的东西,我在这里阅读了其他几个略有不同的问题,所以我想我会发帖。

Java 1.5,我不认为这有什么不同。

Java JAR 战争

评论

1赞 Dan 12/4/2009
还没有尝试过这个,但是在清单中添加“类路径”条目怎么样?
0赞 unorsk 12/4/2009
你有什么原因吗?为什么不尝试保留两个不同的程序集 - 一个用于 Web,一个作为独立应用程序?
0赞 Murali VP 12/4/2009
您是否尝试在具有 WEB-INF/classes 的 manifest.mf 中放置一个类路径,并将 Main-Class 保留为 mypackage。MyEntryPoint类?
0赞 Simon 12/4/2009
尝试了类路径的想法,没有用
0赞 Simon 12/4/2009
@Andrew,我可以有两个不同的包,当一个包的内容是另一个包内容的超集时,这似乎是浪费

答:

7赞 Jason Gritman 12/4/2009 #1

在存档文件中查找类的规则是,文件的包声明的位置和文件在存档中的位置必须匹配。由于您的类位于 WEB-INF/classes 中,因此它认为该类在当前上下文中运行无效。

您可以按照要求执行任务的唯一方法是重新打包 war,以便文件位于存档根目录的目录中,而不是 WEB-INF/classes 目录中。但是,如果这样做,您将无法再从任何 Web 类访问该文件。.classmypackage

如果你想在战争中和外部通过 java 命令行重用这个类,请考虑构建一个可以从命令行运行的可执行 jar,然后将该 jar 放在文件的 WEB-INF/lib 目录中。war

10赞 Bozho 12/4/2009 #2

战争是一个网络应用程序。如果要让控制台/独立应用程序重用与 Web 应用程序相同的类,请考虑将共享类打包到 jar 中,可以将其放入 .然后从命令行使用该 jar。 因此,您可以获得两个控制台应用程序,并且可以在 servlet 中使用相同的类,而无需创建两个不同的包。 当然,当战争爆发时,情况确实如此。WEB-INF/lib

评论

0赞 vikingsteve 11/28/2018
当然,但这并不总是可能的。有时你只有一场战争,想快速运行主类。
0赞 Chad Okere 12/4/2009 #3

好吧,根据维基百科,使用 WAR 文件,加载到类路径中的类位于“/WEB-INF/classes”和“/WEB-INF/lib”目录中。

您可以尝试简单地将类的副本放在 zip 文件的根文件系统上(这就是 war/jar 是什么)。我不确定这是否可行。

您始终可以只创建两个单独的文件。

评论

0赞 Bozho 12/4/2009
将副本放在公共场所绝对是丑陋的
56赞 Yonatan Maman 9/27/2010 #4

您可以执行 Hudson(持续集成项目)所做的工作。 您下载了一个可以在 Tomcat 中部署或使用

java -jar hudson.war

(因为它有一个嵌入式 Jetty 引擎,所以从命令行运行它会导致服务器启动。无论如何,通过查看 hudson 的清单,我了解到他们在存档的根目录中放置了一个 Main 类。在你的情况下,你的战争布局应该是这样的:

在根目录下:

  • mypackage/MyEntryPointClass.class
  • WEB-INF/库
  • WEB-INF/类
  • 元 INF/清单。分子式

而清单应包括以下行:

Main-Class: mypackage.MyEntryPointClass

请注意,mypackage/MyEntryPointClass.class 只能从命令行访问,而 WEB-INF/classes 下的类只能从应用程序服务器访问。

HTH型

评论

2赞 Baruch Atta 8/29/2018
不会投反对票,因为答案包含一些好信息。但是,它没有回答最初的问题“......从命令行作为独立应用程序运行...”
6赞 marioosh 4/20/2011 #5

在 Maven 项目中,您可以使用 Maven War 插件自动构建 jar,方法是将 设置为 。示例如下。archiveClassestrue

<plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-war-plugin</artifactId>
       <configuration>
        <archiveClasses>true</archiveClasses>
       </configuration>
</plugin>

评论

0赞 Shondeslitch 11/19/2018
运行 Maven 全新安装
8赞 Richard Detsch 4/5/2012 #6

要从已部署的 war 文件执行,请执行以下操作:SomeClass.main(String [] args)

  1. 编写具有 main 方法方法的类,即 (public static void main(String[] args) {...}SomeClass.java)
  2. 部署 WAR
  3. cd /usr/local/<yourprojectsname>/tomcat/webapps/projectName/WEB-INF
  4. java -cp "lib/jar1.jar:lib/jar2.jar: ... :lib/jarn.jar" com.mypackage.SomeClass arg1 arg2 ... arg3

注意 1:要查看类是否在运行中:SomeOtherClass.class/usr/tomcat/webapps/<projectName>/WEB-INF/lib

cd /usr/tomcat/webapps/projectName/WEB-INF/lib && 
find . -name '*.jar' | while read jarfile; do if jar tf "$jarfile" | grep SomeOtherClass.class; then echo "$jarfile"; fi; done 

注意 2:写入标准输出,以便您可以通过控制台的 print 语句查看您的主文件是否实际有效。这称为后门。

注3:Bozhidar Bozhanov的上述评论似乎是正确的

评论

1赞 JBCP 12/7/2012
这在技术上是正确的,所以我给它打了+1,但我认为这个解决方案不是一个好主意。它需要手动构建类路径,并且非常容易出错。
0赞 BxlSofty 5/26/2017
同意上述JBCP。但是我正在使用 Netbeans,您可以在其中询问 Java 类的属性,并且它有一个运行时类路径条目,用于收集完整的绝对类路径(我的是 4000 个字符:) )将 Web 应用程序的一些内部结构转换为可编写脚本的类的好方法。
-3赞 Rawat 6/8/2015 #7

无法从 WAR 文件运行 java 类。WAR 文件的结构与 Jar 文件不同。

要查找相关的 Java 类,请导出(首选使用 ant 的方式)它们,就像 Jar 将其放入 Web 应用程序库中一样。

然后,您可以像往常一样使用jar文件来运行java程序。Web 应用程序中也引用了相同的 jar(如果您将此 jar 放在 Web 应用程序库中)

65赞 Bojan Petkovic 10/22/2015 #8

类似于 Richard Detsch,但更容易遵循(也适用于软件包)

第 1 步:解压缩 War 文件。

jar -xvf MyWar.war

第 2 步:移动到目录中

cd WEB-INF

第 3 步:使用所有依赖项运行主数据库

java -classpath "lib/*:classes/." my.packages.destination.FileToRun

评论

0赞 AdamSkywalker 3/17/2018
我一直在寻找的答案
0赞 Sridhar Sarnobat 7/24/2018
这可以在不解压缩的情况下完成吗?我运行我的东西的环境比这更严格。
9赞 ksrb 2/15/2019
对于 Windows,请更改上述命令,因此上述命令将变得特别更改: -> ;java -classpath "lib/*;classes/." my.packages.destination.FileToRun
10赞 Anthony O. 2/16/2016 #9

如果您使用的是 Maven,只需按照有关“如何创建包含 Web 应用程序中的类的 JAR”的文档进行操作:将 <attachClasses>true</attachClasses> 添加到插件的maven-war-plugin<configuration>

<project>
  ...
  <artifactId>mywebapp</artifactId>
  <version>1.0-SNAPSHOT</version>
  ...
  <build>
    <plugins>
      <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.6</version>
    <configuration>
      <attachClasses>true</attachClasses>
    </configuration>
      </plugin>
    </plugins>
  </build>
  ...
</project>

文件夹中将有 2 个产品:target/

  • 本身project.war
  • 在一个 jar 中包含所有已编译的类project-classes.jar

然后,您将能够使用经典方法执行主类:java -cp target/project-classes.jar 'com.mycompany.MainClass' param1 param2

2赞 Rick 3/25/2020 #10

使用 Spring Boot 的最佳方式是:

1/ 创建一个 ServletInitializer 扩展 SpringBootServletInitializer 类 .使用方法配置运行应用程序类的方法

2/ 始终生成一个 maven 安装 WAR 文件

3/ 有了这个人工制品,你甚至可以:

    . start application from war file with java -jar file.war

    . put your war file in your favorite Web App server (like tomcat, ...)
0赞 Alexandr 8/11/2021 #11

作为替代选项,将 rest 服务包含在文件中,以通过 url 触发应用程序逻辑。将文件部署到所需的任何 Web/应用程序服务器上。warwar

然后,您可以通过任何基于命令行的 HTTP 客户端(如在 Linux 上)启动应用程序。curl

缺点:通常这些 HTTP 客户端在不同的操作系统上是不同的。这在很多情况下并不重要。您也可以在 Windows 上安装。curl

0赞 Efrain 10/20/2023 #12

使用 docker 的解决方案:

docker run --rm -it -v ${PWD}:/usr/local/tomcat/webapps -p 8080:8080 tomcat

这是 Windows 语法 - 对于 Linux/Mac,请将 ${PWD} 替换为 $(pwd)。

.war 文件是一个 Java Servlet Web 应用程序归档文件,它应该在所谓的 servlet 容器中运行,这实际上意味着 Apache Tomcat。最简单的方法是简单地运行 Tomcat,我们可以使用 docker 和上述命令来完成。不幸的是,我没有运气运行我试图运行的(旧版)应用程序 - 我认为这是 Servlet-API 版本的不匹配。