简体   繁体   English

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

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

I have a Java class which has a main and I used to run as a standalone app from the command line eg我有一个 Java 类,它有一个 main,我曾经从命令行作为独立应用程序运行,例如

java -jar myjar.jar params

I needed to repackage the code to run under apache and all my code, including the entry point class from the old jar, has ended up in a WAR file for easy deplyment into the web server.我需要重新打包代码以在 apache 下运行,并且我的所有代码,包括来自旧 jar 的入口点类,都以 WAR 文件结束,以便轻松部署到 Web 服务器中。

However, I still want to be able to run it from the command line and the code has not changed and is all in there, I just can't figure out how to get it to run.但是,我仍然希望能够从命令行运行它并且代码没有改变并且全部在那里,我只是不知道如何让它运行。

Here's what I tried...这是我尝试过的...

I presumed the WAR was just like a jar, so我认为战争就像一个罐子,所以

java -jar mywar.war params

That failed saying there was no main class defined in the manifest.未能说明清单中没有定义主类。

I manually added a manifest to the war and tried again, with the same effect.我手动向战争添加了一个清单并再次尝试,具有相同的效果。

I noticed that in my war I had a folder called META-INF containing a manifest.mf, so I added a line to that declaring my main class as I would to a normal manifest...我注意到在我的战争中我有一个名为 META-INF 的文件夹,其中包含一个 manifest.mf,所以我添加了一行来声明我的主类,就像我对普通清单一样......

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

This gave a noClassDefFoundError mypackage.MyEntryPointClass , which is progress of a sort.这给出了一个noClassDefFoundError mypackage.MyEntryPointClass ,这是一种进步。 That led me to believe that it was just a path issue, so I tried这让我相信这只是一个路径问题,所以我尝试了

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

I now get the same error, but with a stack trace...我现在得到同样的错误,但有一个堆栈跟踪......

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)

I've googled for a bit but can't find anything which answers my question, and I read a couple of other questions here which are slightly different, so I thought I would post.我用谷歌搜索了一下,但找不到任何可以回答我的问题的内容,我在这里阅读了一些其他问题,这些问题略有不同,所以我想我会发布。

Java 1.5, not that I think that should make any difference. Java 1.5,不是我认为应该有什么不同。

Similar to what Richard Detsch but with a bit easier to follow (works with packages as well)类似于 Richard Detsch,但更容易理解(也适用于包)

Step 1: Unwrap the War file.第 1 步:解开 War 文件。

jar -xvf MyWar.war

Step 2: move into the directory第二步:进入目录

cd WEB-INF

Step 3: Run your main with all dependendecies第 3 步:运行包含所有依赖项的 main

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

You can do what Hudson (continuous integration project) does.您可以执行Hudson (持续集成项目)所做的工作。 you download a war which can be deployed in tomcat or to execute using您下载了一个可以部署在 tomcat 中或使用执行的战争

java -jar hudson.war

(Because it has an embedded Jetty engine, running it from command line cause a server to be launched.) Anyway by looking at hudson's manifest I understand that they put a Main class in the root for the archive. (因为它有一个嵌入式 Jetty 引擎,从命令行运行它会导致启动服务器。)无论如何,通过查看 hudson 的清单,我知道他们将 Main 类放在存档的根目录中。 In your case your war layout should be look like:在您的情况下,您的战争布局应如下所示:

under root:在根下:

  • mypackage/MyEntryPointClass.class mypackage/MyEntryPointClass.class
  • WEB-INF/lib网络信息/库
  • WEB-INF/classes WEB-INF/类
  • META-INF/MANIFEST.MF元信息/清单.MF

while the manifest should include the following line:而清单应包括以下行:

Main-Class: mypackage.MyEntryPointClass

please notice that the mypackage/MyEntryPointClass.class is accessable from the command line only, and the classes under WEB-INF/classes are accessable from the application server only.请注意 mypackage/MyEntryPointClass.class 只能从命令行访问,而 WEB-INF/classes 下的类只能从应用服务器访问。

HTH HTH

A war is a webapp.战争是一个网络应用程序。 If you want to have a console/standalone application reusing the same classes as you webapp, consider packaging your shared classes in a jar, which you can put in WEB-INF/lib .如果您想让控制台/独立应用程序重用与 web 应用程序相同的类,请考虑将共享类打包在 jar 中,您可以将其放入WEB-INF/lib Then use that jar from the command line.然后从命令行使用该 jar。 Thus you get both your console application, and you can use the same classes in your servlets, without making two different packages.因此,您可以获得控制台应用程序,并且可以在 servlet 中使用相同的类,而无需制作两个不同的包。 This, of course, is true when the war is exploded.当然,这在战争爆发时是正确的。

To execute SomeClass.main(String [] args) from a deployed war file do:要从部署的 war 文件执行SomeClass.main(String [] args) ,请执行以下操作:

  1. Write class SomeClass.java that has a main method method ie ( public static void main(String[] args) {...} )编写具有主要方法方法的类SomeClass.java ,即( public static void main(String[] args) {...}
  2. Deploy your WAR部署您的 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

Note1: to see if the class SomeOtherClass.class is in /usr/tomcat/webapps/<projectName>/WEB-INF/lib run:注意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 

Note2: Write to standard out so you can see if your main actually works via print statements to the console.注意2:写入标准输出,以便您可以通过控制台的打印语句查看您的主要内容是否确实有效。 This is called a back door.这称为后门。

Note3: The comment above by Bozhidar Bozhanov seems correct注3: Bozhidar Bozhanov 上面的评论似乎是正确的

If you're using Maven, just follow the maven-war-plugin documentation about " How do I create a JAR containing the classes in my webapp? ": add <attachClasses>true</attachClasses> to the <configuration> of the plugin:如果您使用的是 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>

The you will have 2 products in the target/ folder:您将在target/文件夹中有 2 个产品:

  • The project.war itself project.war本身
  • The project-classes.jar which contains all the compiled classes in a jar project-classes.jar包含 jar 中所有已编译的类

Then you will be able to execute a main class using classic method: java -cp target/project-classes.jar 'com.mycompany.MainClass' param1 param2然后您将能够使用经典方法执行主类: java -cp target/project-classes.jar 'com.mycompany.MainClass' param1 param2

The rules of locating classes in an archive file is that the location of the file's package declaration and the location of the file within the archive have to match.在存档文件中定位类的规则是文件的包声明的位置和存档中文件的位置必须匹配。 Since your class is located in WEB-INF/classes, it thinks the class is not valid to run in the current context.由于您的类位于 WEB-INF/classes 中,因此它认为该类在当前上下文中运行无效。

The only way you can do what you're asking is to repackage the war so the .class file resides in the mypackage directory in the root of the archive rather than the WEB-INF/classes directory.您可以执行您所要求的唯一方法是重新打包战争,以便.class文件驻留在存档根目录的mypackage目录中,而不是 WEB-INF/classes 目录中。 However, if you do that you won't be able to access the file from any of your web classes anymore.但是,如果这样做,您将无法再从任何 Web 类访问该文件。

If you want to reuse this class in both the war and outside from the java command line, consider building an executable jar you can run from the command line, then putting that jar in the war file's WEB-INF/lib directory.如果您想从 java 命令行在 war 和外部重用此类,请考虑构建一个可以从命令行运行的可执行 jar,然后将该 jar 放在war文件的 WEB-INF/lib 目录中。

In Maven project, You can build jar automatically using Maven War plugin by setting archiveClasses to true .Maven项目中,您可以通过将archiveClasses设置为true来使用Maven War 插件自动构建 jar。 Example below.下面举例。

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

the best way if you use Spring Boot is :如果您使用 Spring Boot,最好的方法是:

1/ Create a ServletInitializer extends SpringBootServletInitializer Class . 1/ 创建一个 ServletInitializer 扩展SpringBootServletInitializer类。 With method configure which run your Application Class使用方法配置运行您的应用程序类

2/ Generate always a maven install WAR file 2/总是生成一个 maven 安装WAR文件

3/ With this artefact you can even : 3/ 有了这个人工制品,您甚至可以:

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

    . put your war file in your favorite Web App server (like tomcat, ...)

Well, according to Wikipedia , with a WAR file, the classes that get loaded into the classpath are in the "/WEB-INF/classes" and "/WEB-INF/lib" directory.好吧,根据Wikipedia ,使用 WAR 文件,加载到类路径中的类位于“/WEB-INF/classes”和“/WEB-INF/lib”目录中。

You could try simply putting a copy of the classes on the root file system of the zip file (which is what a war/jar is).您可以尝试简单地将类的副本放在 zip 文件的根文件系统上(这就是 war/jar 的内容)。 I'm not sure if that would work though.我不确定这是否可行。

You can always just create two separate files.您始终可以只创建两个单独的文件。

As an alternative option, include into the war file, the rest service to trigger the application logic via url.作为替代选项,将其余服务包含到war文件中以通过 url 触发应用程序逻辑。 Deploy the war file onto any web/application server you want.war文件部署到您想要的任何 Web/应用程序服务器上。

Then you can start your application via any command-line based HTTP client like curl on Linux.然后,您可以通过任何基于命令行的 HTTP 客户端(如 Linux 上的curl启动您的应用程序。

The disadvantage: usually these HTTP clients are different on different OSs.缺点:通常这些 HTTP 客户端在不同的操作系统上是不同的。 Which is not critical for a lot of cases.这对于很多情况来说并不重要。 Also you can install curl on Windows.您也可以在 Windows 上安装curl

It's not possible to run a java class from a WAR file.无法从 WAR 文件运行 java 类。 WAR files have a different structure to Jar files. WAR 文件与 Jar 文件具有不同的结构。

To find the related java classes, export (preferred way to use ant) them as Jar put it in your web app lib.要查找相关的 Java 类,请导出(使用 ant 的首选方式)它们,因为 Jar 将其放入您的 Web 应用程序库中。

Then you can use the jar file as normal to run java program.然后就可以正常使用jar文件运行java程序了。 The same jar was also referred in web app (if you put this jar in web app lib)在 web app 中也引用了同一个 jar(如果你把这个 jar 放在 web app lib 中)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM