Wie führe ich eine Klasse in einem WAR über die Befehlszeile aus?

76

Ich habe eine Java-Klasse mit einer Hauptklasse und habe sie früher als eigenständige App über die Befehlszeile ausgeführt, z

java -jar myjar.jar params

Ich musste den Code neu packen, um unter Apache ausgeführt zu werden, und mein gesamter Code, einschließlich der Einstiegspunktklasse aus dem alten JAR, wurde zur einfachen Bereitstellung auf dem Webserver in einer WAR-Datei gespeichert.

Ich möchte es jedoch weiterhin über die Befehlszeile ausführen können, und der Code hat sich nicht geändert und ist alles enthalten. Ich kann nur nicht herausfinden, wie ich es zum Laufen bringen kann.

Folgendes habe ich versucht ...

Ich nahm an, dass der KRIEG wie ein Glas war

java -jar mywar.war params

Das scheiterte daran zu sagen, dass im Manifest keine Hauptklasse definiert war.

Ich habe dem Krieg manuell ein Manifest hinzugefügt und es erneut versucht, mit dem gleichen Effekt.

Ich bemerkte, dass ich in meinem Krieg einen Ordner namens META-INF hatte, der eine manifest.mf enthielt, also fügte ich eine Zeile hinzu, in der meine Hauptklasse wie in einem normalen Manifest deklariert wurde ...

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

Dies ergab noClassDefFoundError mypackage.MyEntryPointClasseine Art Fortschritt. Das ließ mich glauben, dass es nur ein Pfadproblem war, also versuchte ich es

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

Ich bekomme jetzt den gleichen Fehler, aber mit einem 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)

Ich habe ein bisschen gegoogelt, kann aber nichts finden, was meine Frage beantwortet, und ich habe hier ein paar andere Fragen gelesen, die etwas anders sind, also dachte ich, ich würde etwas posten.

Java 1.5, nicht dass ich denke, dass das einen Unterschied machen sollte.

Simon
quelle
1
Ich habe es noch nicht versucht, aber wie wäre es, wenn Sie dem Manifest einen 'Klassenpfad'-Eintrag hinzufügen?
Dan
Hast du irgendwelche Gründe dafür? Warum versuchen Sie nicht, zwei verschiedene Assemblys zu behalten - eine für das Web und eine als eigenständige Anwendung?
Andrii
Haben Sie versucht, einen Klassenpfad in die manifest.mf mit WEB-INF / classes einzufügen und die Hauptklasse als mypackage.MyEntryPointClass zu belassen?
Murali VP
versuchte die Klassenpfad Idee, funktionierte nicht
Simon
@ Andrew, ich könnte zwei verschiedene Pakete haben, es scheint nur verschwenderisch, wenn der Inhalt des einen eine Obermenge des Inhalts des anderen ist
Simon

Antworten:

49

Ähnlich wie Richard Detsch, aber etwas einfacher zu befolgen (funktioniert auch mit Paketen)

Schritt 1: Packen Sie die War-Datei aus.

jar -xvf MyWar.war

Schritt 2: Wechseln Sie in das Verzeichnis

cd WEB-INF

Schritt 3: Führen Sie Ihr main mit allen Abhängigkeiten aus

java -classpath "lib/*:classes/." my.packages.destination.FileToRun
Bojan Petkovic
quelle
die Antwort, die ich suchte
AdamSkywalker
Kann dies ohne Entpacken erfolgen? Die Umgebung, in der ich meine Sachen laufen lasse, ist strenger.
Sridhar Sarnobat
4
Für Windows ändern Sie den, : -> ;so dass der obige Befehl java -classpath "lib/*;classes/." my.packages.destination.FileToRunspeziell geändert wird
ksrb
45

Sie können das tun, was Hudson (Continuous Integration Project) tut. Sie laden einen Krieg herunter, der in Tomcat bereitgestellt oder mit ausgeführt werden kann

java -jar hudson.war

(Da es eine eingebettete Jetty-Engine hat, wird durch Ausführen über die Befehlszeile ein Server gestartet.) Wenn ich mir das Hudson-Manifest anschaue, verstehe ich, dass sie eine Hauptklasse im Stammverzeichnis für das Archiv ablegen. In Ihrem Fall sollte Ihr Kriegslayout folgendermaßen aussehen:

unter der Wurzel:

  • mypackage / MyEntryPointClass.class
  • WEB-INF / lib
  • WEB-INF / Klassen
  • META-INF / MANIFEST.MF

während das Manifest die folgende Zeile enthalten sollte:

Main-Class: mypackage.MyEntryPointClass

Bitte beachten Sie, dass auf mypackage / MyEntryPointClass.class nur über die Befehlszeile zugegriffen werden kann und auf die Klassen unter WEB-INF / classes nur über den Anwendungsserver zugegriffen werden kann.

HTH

Yonatan Maman
quelle
1
Ich werde nicht abstimmen, weil die Antwort einige gute Informationen enthält. Es beantwortet jedoch nicht die ursprüngliche Frage "... als eigenständige App über die Befehlszeile ausführen ..."
Baruch Atta
10

Ein Krieg ist eine Webapp. Wenn Sie möchten, dass eine Konsole / eigenständige Anwendung dieselben Klassen wie Ihre Webanwendung wiederverwendet, sollten Sie Ihre freigegebenen Klassen in eine JAR-Datei packen, die Sie einfügen können WEB-INF/lib. Verwenden Sie dann das Glas über die Befehlszeile. Auf diese Weise erhalten Sie beide Konsolenanwendungen und können dieselben Klassen in Ihren Servlets verwenden, ohne zwei verschiedene Pakete zu erstellen. Dies gilt natürlich, wenn der Krieg explodiert.

Bozho
quelle
Sicher, aber das ist nicht immer möglich. Manchmal hat man nur einen Krieg und möchte die Hauptklasse schnell leiten.
Wikingersteve
9

Um SomeClass.main (String [] args) aus einer bereitgestellten Kriegsdatei auszuführen, gehen Sie wie folgt vor:

Schritt 1: Schreiben Sie die Klasse SomeClass.java mit einer Hauptmethodenmethode, dh (public static void main (String [] args) {...})

Schritt 2: Stellen Sie Ihr WAR bereit

Schritt 3: cd / usr / local / yourprojectsname / tomcat / webapps / projectName / WEB-INF

Schritt 4: java -cp "lib / jar1.jar: lib / jar2.jar: ...: lib / jarn.jar" com.mypackage.SomeClass arg1 arg2 ... arg3

Hinweis 1: (um festzustellen, ob sich die Klasse SomeOtherClass.class in / usr / tomcat / webapps / projectName / WEB-INF / lib befindet)

Führen Sie -> cd / usr / tomcat / webapps / projectName / WEB-INF / lib && find aus. -name '* .jar' | während gelesen jarfile; tun, wenn jar tf "$ jarfile" | grep SomeOtherClass.class; dann echo "$ jarfile"; fi; erledigt

Hinweis 2: Schreiben Sie in Standard Out, damit Sie über print-Anweisungen an die Konsole sehen können, ob Ihr Main tatsächlich funktioniert. Dies nennt man eine Hintertür.

Anmerkung 3: Der obige Kommentar von Bozhidar Bozhanov scheint richtig zu sein

Richard Detsch
quelle
1
Das ist technisch korrekt, also habe ich es mit +1 bewertet, aber ich denke nicht, dass diese Lösung eine gute Idee ist. Es erfordert das manuelle Erstellen eines Klassenpfads und ist sehr fehleranfällig.
JBCP
Zustimmung zu JBCP oben. Aber ich benutze Netbeans und dort können Sie nach den Eigenschaften Ihrer Java-Klasse fragen, und sie hat einen Runtime Classpath-Eintrag, der den vollständigen absoluten Klassenpfad sammelt (meiner ist 4000 Zeichen :)). Eine gute Möglichkeit, einige Interna von zu drehen Ihre Webanwendung in skriptfähige Klassen.
BxlSofty
6

Die Regeln zum Auffinden von Klassen in einer Archivdatei lauten, dass der Speicherort der Paketdeklaration der Datei und der Speicherort der Datei im Archiv übereinstimmen müssen. Da sich Ihre Klasse in WEB-INF / classes befindet, ist die Ausführung der Klasse im aktuellen Kontext möglicherweise nicht gültig.

Die einzige Möglichkeit, das zu tun, was Sie verlangen, besteht darin, den Krieg neu zu packen, sodass sich die .classDatei im mypackageVerzeichnis im Stammverzeichnis des Archivs und nicht im Verzeichnis WEB-INF / classes befindet. In diesem Fall können Sie jedoch von keiner Ihrer Webklassen mehr auf die Datei zugreifen.

Wenn Sie diese Klasse sowohl im Krieg als auch außerhalb der Java-Befehlszeile wiederverwenden möchten, sollten Sie eine ausführbare JAR- warDatei erstellen, die Sie über die Befehlszeile ausführen können, und diese JAR- Datei dann in das Verzeichnis WEB-INF / lib der Datei einfügen.

Jason Gritman
quelle
6

Wenn Sie Maven verwenden, folgen Sie einfach der maven-war-pluginDokumentation über „ Wie erstelle ich eine JAR - Klassen in meinem Webapp enthalten? “: Add <attachClasses>true</attachClasses>auf die <configuration>des Plug - ins:

<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>

Sie haben 2 Produkte im target/Ordner:

  • Das project.warselbst
  • Das project-classes.jarenthält alle kompilierten Klassen in einem Glas

Dann können Sie eine Hauptklasse mit der klassischen Methode ausführen: java -cp target/project-classes.jar 'com.mycompany.MainClass' param1 param2

Anthony O.
quelle
5

In Maven - Projekt können Sie jar bauen automatisch mit Maven War Plugin , indem Sie archiveClassesauf true. Beispiel unten.

<plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-war-plugin</artifactId>
       <configuration>
        <archiveClasses>true</archiveClasses>
       </configuration>
</plugin>
Marioosh
quelle
Führen Sie Maven Clean Install
Shondeslitch
1

Der beste Weg, wenn Sie Spring Boot verwenden, ist:

1 / ServletInitializer erstellen erweitert die SpringBootServletInitializer- Klasse. Mit der Methode konfigurieren Sie, welche Ihre Anwendungsklasse ausführen

2 / Generieren Sie immer eine Maven-Installations- WAR- Datei

3 / Mit diesem Artefakt können Sie sogar:

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

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

Laut Wikipedia befinden sich die Klassen, die in den Klassenpfad geladen werden, mit einer WAR-Datei im Verzeichnis "/ WEB-INF / classes" und "/ WEB-INF / lib".

Sie können versuchen, einfach eine Kopie der Klassen in das Root-Dateisystem der Zip-Datei zu stellen (was ein War / Jar ist). Ich bin mir nicht sicher, ob das funktionieren würde.

Sie können immer nur zwei separate Dateien erstellen.

Chad Okere
quelle
Kopien an einem öffentlichen Ort zu platzieren wäre definitiv hässlich
Bozho
-3

Es ist nicht möglich, eine Java-Klasse aus einer WAR-Datei auszuführen. WAR-Dateien haben eine andere Struktur als Jar-Dateien.

Um die zugehörigen Java-Klassen zu finden, exportieren Sie sie (bevorzugte Methode zur Verwendung von ant), wie Jar sie in Ihre Web-App-Bibliothek einfügt.

Dann können Sie die JAR-Datei wie gewohnt verwenden, um das Java-Programm auszuführen. Das gleiche Glas wurde auch in der Web-App verwendet (wenn Sie dieses Glas in die Web-App lib einfügen).

Rawat
quelle