Wie lege ich mit Maven alle erforderlichen JAR-Dateien in einen Bibliotheksordner in der endgültigen JAR-Datei?

104

Ich verwende Maven in meiner eigenständigen Anwendung und möchte alle Abhängigkeiten in meiner JAR-Datei in einen Bibliotheksordner packen, wie in einer der Antworten hier erwähnt:

Wie kann ich mit Maven eine ausführbare JAR mit Abhängigkeiten erstellen?

Ich möchte, dass meine endgültige JAR-Datei einen Bibliotheksordner enthält, der die Abhängigkeiten als JAR-Dateien enthält, nicht so, wie maven-shade-plugindie Abhängigkeiten in Form von Ordnern wie der Maven-Hierarchie im Ordner .m2 abgelegt werden.

Eigentlich macht die aktuelle Konfiguration das, was ich will, aber ich habe ein Problem beim Laden der JAR-Dateien beim Ausführen der Anwendung. Ich kann die Klassen nicht laden.

Hier ist meine Konfiguration:

<plugins>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>copy-dependencies</id>
                <phase>prepare-package</phase>
                <goals>
                    <goal>copy-dependencies</goal>
                </goals>
                <configuration>
                    <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                    <overWriteReleases>false</overWriteReleases>
                    <overWriteSnapshots>false</overWriteSnapshots>
                    <overWriteIfNewer>true</overWriteIfNewer>
                </configuration>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
            <archive>
                <manifest>
                    <addClasspath>true</addClasspath>
                    <classpathPrefix>lib/</classpathPrefix>
                    <mainClass>com.myapp.MainClass</mainClass>
                </manifest>
            </archive>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>install</id>
                <phase>install</phase>
                <goals>
                    <goal>sources</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>

</plugins>

Das Projekt läuft einwandfrei von Eclipse aus, und die JAR-Dateien werden wie gewünscht im Bibliotheksordner in meiner endgültigen JAR-Datei abgelegt. Wenn ich jedoch die endgültige JAR-Datei aus dem Zielordner ausführe, erhalte ich immer Folgendes ClassNotFoundException:

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext
        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)
Could not find the main class: com.myapp.MainClass. Program will exit.

Wie kann ich diese Ausnahme beheben?

Mahmoud Saleh
quelle
1
Mit welchem ​​Befehl führen Sie das Glas aus? wahrscheinlich bevorzugen Sie maven exec Plugin?
Andrey Borisov
Ist die Ausnahmemeldung im Vergleich zur POM-Datei veraltet? Es scheint, dass die Hauptklasse com.myapp.MainClassgesucht wird, nicht com.tastycafe.MainClass.
Duncan Jones
@ Duncan Jones, Problem beim Kopieren und Einfügen, ich habe die Frage bearbeitet
Mahmoud Saleh
3
Beachten Sie, dass die Standard-Klassenlader in Java diese nicht verstehen können, wenn Sie Gläser im Glas haben möchten.
Thorbjørn Ravn Andersen
Wie werden die Maven-Abhängigkeiten in einem lib-Ordner außerhalb der JAR platziert?
ed22

Antworten:

81

Das Folgende ist meine Lösung. Testen Sie es, wenn es für Sie funktioniert:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <!-- <classpathPrefix>lib</classpathPrefix> -->
                <!-- <mainClass>test.org.Cliente</mainClass> -->
            </manifest>
            <manifestEntries>
                <Class-Path>lib/</Class-Path>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

Das erste Plugin legt alle Abhängigkeiten im Ordner target / classes / lib ab, das zweite enthält den Bibliotheksordner in der endgültigen JAR-Datei und konfiguriert die Manifest.mfDatei.

Dann müssen Sie jedoch benutzerdefinierten Klassenladecode hinzufügen, um die JAR-Dateien zu laden.

Um ein benutzerdefiniertes Laden von Klassen zu vermeiden, können Sie "$ {project.build.directory} / lib" verwenden. In diesem Fall haben Sie jedoch keine Abhängigkeiten in der endgültigen JAR-Datei, wodurch der Zweck zunichte gemacht wird.

Es ist zwei Jahre her, seit die Frage gestellt wurde. Das Problem verschachtelter JAR-Dateien besteht dennoch. Ich hoffe es hilft jemandem.

gmode
quelle
1
Verwendung: mvn install, cd target, java -jar MyJarFile-1.0.jar
djb
was vermisse ich Dadurch wird ein Manifest-Klassenpfadeintrag erstellt, der "lib /" und alle einzelnen JARs aus dem lib-Ordner enthält. Ist das beabsichtigt? Warum?
Gapvision
2
Es funktionierte, nachdem ich "$ {project.build.directory} / classes / lib" in $ {project.build.directory} / lib geändert hatte
Rajendra Thorat
1
Leider schließt Abhängigkeiten ein, die als bereitgestellt deklariert wurden.
Philippe Gioseffi
@ Rajendra danke, das hat geholfen: $ {project.build.directory} / lib
Mindaugas K.
30

Aktualisiert:

<build> 
  <plugins> 
    <plugin> 
    <artifactId>maven-dependency-plugin</artifactId> 
    <executions> 
      <execution> 
        <phase>install</phase> 
          <goals> 
            <goal>copy-dependencies</goal> 
          </goals> 
          <configuration> 
             <outputDirectory>${project.build.directory}/lib</outputDirectory> 
          </configuration> 
        </execution> 
      </executions> 
    </plugin> 
  </plugins> 
</build> 
Ahmet Karakaya
quelle
4
Dies platziert den lib-Ordner außerhalb des JAR (was nicht das ist, was ich will). ist das besser als die lib in das glas zu stecken? und wie kann die Anwendung in diesem Fall an den Kunden geliefert werden?
Mahmoud Saleh
es ist mir jetzt klarer. Lassen Sie mich eine Google-Suche durchführen. Aber ich würde gerne wissen, warum Sie alle Abhängigkeits-JAR-Dateien in den angegebenen Ordner innerhalb der ausführbaren JAR-Datei kopieren möchten. Wenn sich alle Abhängigkeits-JAR-Dateien in der JAR-Datei befinden, warum müssen Sie sie in einem lib-Ordner suchen?
Ahmet Karakaya
23

Der einfachste und effizienteste Weg ist die Verwendung eines Uber-Plugins wie folgt:

          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <finalName>uber-${artifactId}-${version}</finalName>
            </configuration>
        </plugin>

Sie haben alle in einer JAR-Datei de-normalisiert.

Andrey Borisov
quelle
Verwenden Sie es zusätzlich zu meiner aktuellen Konfiguration? und was genau macht dieses Plugin?
Mahmoud Saleh
15
Ich möchte nicht, dass meine JAR-Datei so aussieht. Ich möchte, dass alle Abhängigkeiten in einem lib-Ordner in der JAR-Datei enthalten sind, wie dies bei NetBean der Fall ist.
Mahmoud Saleh
12

Das ausführbare Packer Maven Plugin kann genau für diesen Zweck verwendet werden: Erstellen von eigenständigen Java-Anwendungen, die alle Abhängigkeiten als JAR-Dateien in einem bestimmten Ordner enthalten.

Fügen Sie einfach die folgende zu Ihrem pom.xmlInneren des <build><plugins>Abschnitts (achten Sie darauf , den Wert zu ersetzen , mainClassentsprechend):

<plugin>
    <groupId>de.ntcomputer</groupId>
    <artifactId>executable-packer-maven-plugin</artifactId>
    <version>1.0.1</version>
    <configuration>
        <mainClass>com.example.MyMainClass</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>pack-executable-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Die erstellte JAR-Datei befindet sich target/<YourProjectAndVersion>-pkg.jarnach dem Ausführen unter mvn package. Alle Abhängigkeiten zur Kompilierungszeit und zur Laufzeit werden in den lib/Ordner in der JAR-Datei aufgenommen.

Haftungsausschluss: Ich bin der Autor des Plugins.

Cybran
quelle
Ich habe es versucht und ich kann sagen, dass es funktioniert ... Wie Sie sagten, erstellt dieses Plugin eine JAR-Datei mit ihren Bibliotheken (Jars) in einem lib-Verzeichnis im JAR ... Die Konfiguration ist wirklich einfach. Ich denke, es ist was Der Autor dieser Frage erwartet ... Ich werde Ihnen meine Stimme geben ... Der einzige Nachteil, den ich darauf gefunden habe (aus diesem Grund konnte ich sie nicht verwenden), gibt es eine Verzögerung, wenn ich meine ausführe jar und die Anwendung wird angezeigt (ca. 20 Sekunden), wahrscheinlich aufgrund des Prozesses zum Registrieren der Bibliotheken im benutzerdefinierten Klassenladeprogramm ... Aber es ist ein großartiger Ansatz und ein ausgezeichnetes Plugin ...
Adam M. Gamboa G.
3

So mache ich das:

    <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>com.project.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

Und dann renne ich einfach:

mvn assembly:assembly
Eduardo Andrade
quelle
1
Beachten Sie, dass Sie immer vorab kompilieren sollten, da assemblynur das, was sich in "Ziel / Klassen" befindet, in die JAR eingefügt wird. Dadurch wird sichergestellt, dass die JAR alle Änderungen enthält, die Sie kürzlich am Quellcode vorgenommen haben. Sie sollten also Folgendes tun : mvn clean compile assembly:assembly.
NaXa
2

Ich habe diese Antwort auf die Frage gefunden:

http://padcom13.blogspot.co.uk/2011/10/creating-standalone-applications-with.html

Sie erhalten nicht nur die abhängigen lib-Dateien in einem lib-Ordner, sondern auch einen bin-Director mit einer ausführbaren Unix- und einer dos-Datei.

Die ausführbare Datei ruft Java letztendlich mit einem -cp-Argument auf, das auch alle abhängigen Bibliotheken auflistet.

Das gesamte Los befindet sich in einem Appasembly-Ordner im Zielordner. Epos.

============= Ja, ich weiß, dass dies ein alter Thread ist, aber die Suchergebnisse sind immer noch hoch, daher dachte ich, es könnte jemandem wie mir helfen.

user4815755
quelle
1

Dies ist eindeutig ein Klassenpfadproblem. Beachten Sie, dass sich der Klassenpfad etwas ändern muss, wenn Sie Ihr Programm außerhalb der IDE ausführen. Dies liegt daran, dass die IDE die anderen JARs relativ zum Stammordner Ihres Projekts lädt, während dies im Fall der endgültigen JAR normalerweise nicht der Fall ist.

In diesen Situationen möchte ich die JAR manuell erstellen. Es dauert höchstens 5 Minuten und löst immer das Problem. Ich schlage nicht vor, dass Sie dies tun. Finde einen Weg, Maven zu benutzen, das ist sein Zweck.

Radu Murzea
quelle
@SoboLAN Das manuelle Erstellen der JAR ist hier keine Lösung. Die Absicht ist, Maven zu verwenden, was genau das Gegenteil von "manuell" ist!
Duncan Jones
@ DuncanJones Du hast vollkommen recht. Ich schlage vor, er benutzt Maven, um es zu tun. Ich habe jedoch keine Erfahrung damit und wusste nicht genau, welche Lösung ich empfehlen sollte. Ich habe meine Antwort bearbeitet, um dies widerzuspiegeln.
Radu Murzea