如何从命令行运行 WAR 中的类?
Posted
技术标签:
【中文标题】如何从命令行运行 WAR 中的类?【英文标题】:How do I run a class in a WAR from the command line? 【发布时间】:2010-12-23 00:19:25 【问题描述】:我有一个 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,我认为这不会有什么不同。
【问题讨论】:
没试过,但是在清单中添加一个“类路径”条目怎么样? 你有什么理由吗?为什么不尝试保留两个不同的程序集 - 一个用于 Web,一个作为独立应用程序? 您是否尝试在具有 WEB-INF/classes 的 manifest.mf 中放置一个类路径,并将 Main-Class 保留为 mypackage.MyEntryPointClass ? 尝试了类路径的想法,没有用 @Andrew,我可以有两个不同的包,当一个的内容是另一个的内容的超集时似乎很浪费 【参考方案1】:在存档文件中定位类的规则是文件的包声明的位置和存档中文件的位置必须匹配。由于您的类位于 WEB-INF/classes 中,因此它认为该类在当前上下文中运行无效。
您可以按照您的要求进行操作的唯一方法是重新打包 war,以便 .class
文件位于存档根目录中的 mypackage
目录中,而不是 WEB-INF/classes 目录中。但是,如果您这样做,您将无法再从您的任何网络课程中访问该文件。
如果你想在战争和外部从 java 命令行重用这个类,考虑构建一个可以从命令行运行的可执行 jar,然后将该 jar 放入 war
文件的 WEB-INF/lib目录。
【讨论】:
【参考方案2】:战争是一个网络应用程序。如果您想让控制台/独立应用程序重用与您的 webapp 相同的类,请考虑将您的共享类打包在一个 jar 中,您可以将其放入 WEB-INF/lib
。然后从命令行使用该 jar。
因此,您获得了两个控制台应用程序,并且可以在您的 servlet 中使用相同的类,而无需制作两个不同的包。
当然,战争爆发时也是如此。
【讨论】:
当然,但这并不总是可能的。有时你只有一个战争,想快速运行主类。【参考方案3】:好吧,根据Wikipedia,使用 WAR 文件,加载到类路径中的类位于“/WEB-INF/classes”和“/WEB-INF/lib”目录中。
您可以尝试简单地将类的副本放在 zip 文件的根文件系统上(这就是 war/jar)。我不确定这是否可行。
您总是可以只创建两个单独的文件。
【讨论】:
把副本放在公共场所肯定很丑【参考方案4】:您可以做Hudson(持续集成项目)所做的事情。 您下载一个可以部署在 tomcat 中或使用执行的战争
java -jar hudson.war
(因为它有一个嵌入式 Jetty 引擎,所以从命令行运行它会导致服务器启动。)无论如何,通过查看 hudson 的清单,我了解到他们将 Main 类放在存档的根目录中。在您的情况下,您的战争布局应如下所示:
根目录下:
mypackage/MyEntryPointClass.class WEB-INF/lib WEB-INF/类 META-INF/MANIFEST.MF而清单应包含以下行:
Main-Class: mypackage.MyEntryPointClass
请注意,mypackage/MyEntryPointClass.class 只能从命令行访问,WEB-INF/classes 下的类只能从应用服务器访问。
HTH
【讨论】:
不会投反对票,因为答案包含一些很好的信息。但是,它没有回答原始问题“...从命令行作为独立应用程序运行...”【参考方案5】:在Maven 项目中,您可以通过将archiveClasses
设置为true
来使用Maven War plugin 自动构建jar。下面的例子。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>
【讨论】:
运行 maven 全新安装【参考方案6】:要从已部署的 war 文件中执行 SomeClass.main(String [] args)
,请执行以下操作:
-
编写类
SomeClass.java
,它有一个主方法方法,即(public static void main(String[] args) ...)
部署您的 WAR
cd /usr/local/<yourprojectsname>/tomcat/webapps/projectName/WEB-INF
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:写入标准输出,以便您可以通过打印语句到控制台查看您的 main 是否实际工作。这称为后门。
注3:Bozhidar Bozhanov 上面的评论似乎是正确的
【讨论】:
这在技术上是正确的,所以我给了它一个 +1,但我认为这个解决方案不是一个好主意。它需要手动构建类路径,并且非常容易出错。 同意上面的JBCP。但是我使用的是 Netbeans,在那里你可以询问你的 Java 类的属性,它有一个运行时类路径条目,它收集了完整的绝对类路径(我的是 4000 个字符 :))将您的 webapp 转换为可编写脚本的类。【参考方案7】:无法从 WAR 文件运行 java 类。 WAR 文件的结构与 Jar 文件不同。
要查找相关的 java 类,请将它们导出(使用 ant 的首选方式)作为 Jar 放入您的 Web 应用程序库中。
然后就可以正常使用jar文件来运行java程序了。 Web 应用程序中也引用了相同的 jar(如果您将此 jar 放在 Web 应用程序库中)
【讨论】:
【参考方案8】:类似于 Richard Detsch,但更容易理解(也适用于包)
第 1 步:解开 War 文件。
jar -xvf MyWar.war
第二步:进入目录
cd WEB-INF
第 3 步:运行所有依赖项的 main
java -classpath "lib/*:classes/." my.packages.destination.FileToRun
【讨论】:
我一直在寻找的答案 不解压就可以做到吗?我运行我的东西的环境比这更严格。 对于windows更改: -> ;
所以上面的命令变成java -classpath "lib/*;classes/." my.packages.destination.FileToRun
专门更改【参考方案9】:
如果您使用 Maven,只需按照有关“How do I create a JAR containing the classes in my webapp?”的maven-war-plugin
文档:将<attachClasses>true</attachClasses>
添加到插件的<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>
target/
文件夹中将有 2 个产品:
project.war
本身
project-classes.jar
包含一个 jar 中的所有已编译类
然后您将能够使用经典方法执行主类:java -cp target/project-classes.jar 'com.mycompany.MainClass' param1 param2
【讨论】:
【参考方案10】:如果你使用 Spring Boot,最好的方法是:
1/ 创建一个 ServletInitializer 扩展 SpringBootServletInitializer 类 .使用运行您的应用程序类的方法 configure
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, ...)
【讨论】:
【参考方案11】:作为替代选项,将其余服务包含到war
文件中,以通过url 触发应用程序逻辑。将 war
文件部署到您想要的任何 Web/应用程序服务器上。
然后您可以通过任何基于命令行的 HTTP 客户端(例如 Linux 上的curl
)启动您的应用程序。
缺点:通常这些 HTTP 客户端在不同的操作系统上是不同的。这对很多情况来说并不重要。你也可以在 Windows 上安装curl
。
【讨论】:
以上是关于如何从命令行运行 WAR 中的类?的主要内容,如果未能解决你的问题,请参考以下文章