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


76

我有一个具有主类的Java类,并且我曾经从命令行作为独立应用程序运行,例如

java -jar myjar.jar params

我需要重新包装代码以使其在apache下运行,并且我的所有代码(包括旧jar中的入口点类)都已打包到WAR文件中,以便轻松部署到Web服务器中。

但是,我仍然希望能够从命令行运行它,并且代码没有更改,并且全部存在,只是无法弄清楚如何运行它。

这是我尝试过的...

我以为战争就像罐子一样

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)

我已经在Google上搜索了一下,但找不到能回答我问题的任何东西,并且我在这里阅读了其他几个稍有不同的问题,因此我想发表。

Java 1.5,不是我认为应该有所作为。


1
还没有尝试过,但是如何在清单中添加“ Class-Path”条目呢?

你有什么理由吗?为什么不尝试保留两个不同的程序集-一个用于Web,另一个作为独立应用程序?
andrii

您是否尝试过将类路径放入具有WEB-INF / classes的manifest.mf中,并将Main-Class保留为mypackage.MyEntryPointClass?
Murali副总裁

尝试了类路径的想法,没有用
西蒙(Simon)2009年

@Andrew,我可以有两个不同的程序包,当一个程序的内容是另一个程序的内容的超集时,这似乎是浪费的
Simon

Answers:


49

与Richard Detsch相似,但更容易理解(也适用于软件包)

第1步:解开War文件。

jar -xvf MyWar.war

步骤2:移至目录

cd WEB-INF

步骤3:使用所有依赖项运行主程序

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

我一直在寻找的答案
AdamSkywalker

无需解压缩就能完成吗?我运行自己的东西的环境比这更加严格。
Sridhar Sarnobat,

4
对于Windows,请更改: -> ;上述命令,以使上面的命令java -classpath "lib/*;classes/." my.packages.destination.FileToRun具体更改
-ksrb

45

您可以执行Hudson(连续集成项目)的操作。您下载了可以部署在tomcat或使用以下命令执行的战争

java -jar hudson.war

(因为它具有嵌入式Jetty引擎,所以从命令行运行它会导致服务器启动。)无论如何,通过查看hudson的清单,我知道他们将Main类放在了存档的根目录中。在您的情况下,您的战争布局应类似于:

在根目录下:

  • mypackage / MyEntryPointClass.class
  • WEB-INF /库
  • WEB-INF /类
  • META-INF / MANIFEST.MF

而清单应包含以下行:

Main-Class: mypackage.MyEntryPointClass

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

高温超导


1
不会拒绝投票,因为答案包含一些良好的信息。但是,它无法回答原始问题“ ...从命令行作为独立应用运行...”
Baruch Atta,

10

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


当然可以,但这并不总是可能的。有时您只会打仗,想快速参加主流班。
vikingsteve

9

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

步骤1:编写类SomeClass.java,它具有一个主要方法方法,即(public static void main(String [] args){...})

步骤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 &&查找。名称'* .jar'| 在读取jarfile时;如果jar tf“ $ jarfile” | grep SomeOtherClass.class; 然后回显“ $ jarfile”;fi; 做完了

注意2:写入标准输出,以便您可以通过打印语句在控制台上查看您的主体是否真正起作用。这称为后门。

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


1
从技术上讲这是正确的,所以我给了它+1,但我认为此解决方案不是一个好主意。它需要手动构建类路径,并且非常容易出错。
JBCP

同意上述JBCP。但是我使用的是Netbeans,您可以在其中查询Java类的属性,并且它具有一个Runtime Classpath条目,该条目可以收集完整的绝对类路径(我是4000个字符:)))您的webapp进入可编写脚本的类。
BxlSofty

6

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

可以按要求进行操作的唯一方法是重新包装战争.class文件,以便文件位于mypackage归档文件根目录中的目录中,而不是WEB-INF / classes目录中。但是,如果这样做,您将无法再从任何Web类访问文件。

如果要从Java命令行在war内和外部重用该类,请考虑构建可以从命令行运行的可执行jar,然后将该jar放在war文件的WEB-INF / lib目录中。


6

如果您使用的是Maven,则只需遵循maven-war-plugin有关“如何在我的Web应用程序中创建包含类的JAR? ”文档:将添加<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


5

Maven项目中,可以通过将设置为来使用Maven War插件自动构建jar 。下面的例子。archiveClassestrue

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

运行Maven
全新

1

如果您使用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, ...)

0

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

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

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


将副本放在公共场所绝对是丑陋的
Bozho

-3

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

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

然后,您可以正常使用jar文件运行Java程序。Web应用程序中也引用了同一个jar(如果将此jar放在Web应用程序库中)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.