Einschließen von Abhängigkeiten in ein Glas mit Maven

353

Gibt es eine Möglichkeit, maven (2.0.9) zu zwingen, alle Abhängigkeiten in eine einzelne JAR-Datei aufzunehmen?

Ich habe ein Projekt, das in eine einzelne JAR-Datei eingebaut wird. Ich möchte, dass die Klassen aus Abhängigkeiten auch in das Glas kopiert werden.

Update: Ich weiß, dass ich nicht einfach eine JAR-Datei in eine JAR-Datei aufnehmen kann. Ich suche nach einer Möglichkeit, die als Abhängigkeiten angegebenen Jars zu entpacken und die Klassendateien in meine JAR zu packen.

Rennfahrer
quelle
2
Wie füge ich eine JAR-Datei in die JAR-Datei in Maven ein?
Kush Patel

Antworten:

488

Sie können dies mit dem Maven-Assembly-Plugin mit dem Deskriptor "jar-with-dependencies" tun. Hier ist der relevante Teil aus einer unserer pom.xml, der dies tut:

  <build>
    <plugins>
      <!-- any other plugins -->
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>
John Stauffer
quelle
30
Das attachedZiel ist veraltet. Das singleoder directory-single-Ziel sollte stattdessen bevorzugt werden.
Pascal Thivent
16
directory-singleist jetzt ebenfalls veraltet.
James McMahon
14
Die Verwendung von Single wird auf der offiziellen Website
mateuszb
42
Falls neue MVN-Leute wie ich stecken bleiben, fügen Sie das Plugin zu <Plugins> in <build> hinzu, das sich in <project> befindet.
DA
10
@ Christian.tucker Es gibt eine zweite JAR im Zielverzeichnis, die wie folgt erstellt wurde: ./target/example-0.0.1-SNAPSHOT.jar und ./target/example-0.0.1-SNAPSHOT-jar-with-dependencies.jar
Technokrat
145

Mit Maven 2 können Sie dazu das Maven2 Assembly Plugin verwenden, das eine vordefinierte Deskriptordatei für diesen Zweck enthält und die Sie einfach in der Befehlszeile verwenden können:

mvn assembly:assembly -DdescriptorId=jar-with-dependencies

Wenn Sie dieses JAR ausführbar machen möchten, fügen Sie einfach die auszuführende Hauptklasse zur Plugin-Konfiguration hinzu:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>my.package.to.my.MainClass</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

Wenn Sie diese Assembly als Teil des normalen Erstellungsprozesses erstellen möchten, sollten Sie das Einzel- oder Verzeichnis-Einzelziel (das assemblyZiel sollte NUR über die Befehlszeile ausgeführt werden) an eine Lebenszyklusphase binden ( packagesinnvoll).

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <id>create-my-bundle</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        ...
      </configuration>
    </execution>
  </executions>
</plugin>

Passen Sie das configurationElement an Ihre Bedürfnisse an (z. B. mit dem gesprochenen Manifest).

Pascal Thivent
quelle
Ich versuche genau das, aber das Plugin wird nicht ausgeführt und die JAR-Datei wird nicht erstellt, obwohl der Build reibungslos ausgeführt wird. Gibt es eine häufige Gefahr, bei der ich stecken geblieben sein könnte?
Posdef
6
Es funktioniert für mich, aber ich habe eine Aufgabe. Nach dem Erstellen werden nun zwei Jars erstellt, eines mit der Project-Artefakt-ID-Version und eines mit der Artefakt-ID-Version "Jar-with-Dependencies". Aber ich möchte, dass nur ein Glas gebaut wird. Gibt es einen anderen Weg
Souvik Bhattacharya
38

Wenn Sie eine ausführbare JAR-Datei erstellen möchten, müssen diese auch die Hauptklasse festlegen. Also sollte die vollständige Konfiguration sein.

    <plugins>
            <plugin>
                 <artifactId>maven-assembly-plugin</artifactId>
                 <executions>
                     <execution>
                          <phase>package</phase>
                          <goals>
                              <goal>single</goal>
                          </goals>
                      </execution>
                  </executions>
                  <configuration>
                       <!-- ... -->
                       <archive>
                           <manifest>
                                 <mainClass>fully.qualified.MainClass</mainClass>
                           </manifest>
                       </archive>
                       <descriptorRefs>
                           <descriptorRef>jar-with-dependencies</descriptorRef>
                      </descriptorRefs>
                 </configuration>
         </plugin>
   </plugins>
abdiel
quelle
2
Warum wird der Name jar an "jar-with-dependencies" angehängt?! Problemumgehungen?
Tina J
1
@Tina J Sie können <appendAssemblyId>false</appendAssemblyId>innerhalb des <configuration>Tags hinzufügen , um das Suffix "-jar-with-dependencies" im endgültigen Namen auszuschließen.
ccu
19

Es gibt das Shadow Maven Plugin . Es kann zum Packen und Umbenennen von Abhängigkeiten verwendet werden (um Abhängigkeitsprobleme im Klassenpfad zu vermeiden).

Thomas Jung
quelle
2
Wenn Sie jar-with-dependencies als Teil des Dateinamens nicht mögen.
Kyle
Dies war die beste Antwort für mich .. :)
Anand Varkey Philips
17

Sie können das neu erstellte Glas mithilfe eines <classifier>Tags verwenden.

<dependencies>
    <dependency>
        <groupId>your.group.id</groupId>
        <artifactId>your.artifact.id</artifactId>
        <version>1.0</version>
        <type>jar</type>
        <classifier>jar-with-dependencies</classifier>
    </dependency>
</dependencies>
Lasantha
quelle
14

Wenn Sie (wie ich) den oben beschriebenen Jar-with-Dependencies- Ansatz nicht besonders mögen , ist die von mir bevorzugte Maven-Lösung, einfach ein WAR-Projekt zu erstellen, auch wenn es sich nur um eine eigenständige Java-Anwendung handelt, die Sie erstellen:

  1. Erstellen Sie ein normales Maven-JAR-Projekt, das Ihre JAR-Datei erstellt (ohne die Abhängigkeiten).

  2. Richten Sie außerdem ein Maven-Kriegsprojekt ein (mit nur einer leeren Datei src / main / webapp / WEB-INF / web.xml , wodurch eine Warnung / ein Fehler im Maven-Build vermieden wird), die nur Ihr JAR-Projekt als enthält eine Abhängigkeit, und machen Sie Ihr jar-Projekt zu einem <module>unter Ihrem Kriegsprojekt. (Dieses Kriegsprojekt ist nur ein einfacher Trick, um alle Ihre JAR-Datei-Abhängigkeiten in eine Zip-Datei zu packen.)

  3. Erstellen Sie das Kriegsprojekt, um die Kriegsdatei zu erstellen.

  4. Benennen Sie im Bereitstellungsschritt Ihre .war-Datei einfach in * .zip um und entpacken Sie sie.

Sie sollten jetzt ein lib-Verzeichnis (das Sie verschieben können, wo Sie es möchten) mit Ihrem jar und allen Abhängigkeiten haben, die Sie zum Ausführen Ihrer Anwendung benötigen:

java -cp 'path/lib/*' MainClass

(Der Platzhalter im Klassenpfad funktioniert in Java-6 oder höher.)

Ich denke, dies ist sowohl einfacher in Maven einzurichten (Sie müssen nicht mit dem Assembly-Plugin herumspielen) als auch bietet Ihnen eine klarere Ansicht der Anwendungsstruktur (Sie sehen die Versionsnummern aller abhängigen Jars in einfacher Ansicht und) Vermeiden Sie es, alles in einer einzigen JAR-Datei zu verstopfen.

Rop
quelle
Ist es dasselbe wie Eclipse "Export as Runnable jar"? Da Sie damit auswählen können, "alle Abhängigkeiten mit der JAR zu verpacken", erhalten Sie alle Abhängigkeiten im Ordner project-lib entlang Ihrer JAR-Datei.
WesternGun
@FaithReaper - Es könnte "das gleiche" sein, das habe ich nie versucht. Aber ich denke, wenn Sie Eclipse verwenden, ist es nicht einfach zu skriptieren, was eine Voraussetzung ist, wenn Sie eine automatisierte implementieren möchten Build + Deployment-Pipeline . Lassen Sie beispielsweise Jenkins-Server den Build von Ihrem Git-Quell-Repository oder ähnlichem ausführen.
Rop
12

http://fiji.sc/Uber-JAR bietet eine hervorragende Erklärung der Alternativen:

Es gibt drei gängige Methoden zum Erstellen eines Uber-JAR:

  1. Unschattiert. Entpacken Sie alle JAR-Dateien und packen Sie sie erneut in eine einzelne JAR.
    • Pro: Funktioniert mit dem Standard-Klassenladeprogramm von Java.
    • Con: Dateien, die in mehreren JAR-Dateien mit demselben Pfad vorhanden sind (z. B. META-INF / services / javax.script.ScriptEngineFactory), überschreiben sich gegenseitig und führen zu fehlerhaftem Verhalten.
    • Tools: Maven Assembly Plugin, Klassenwelten Uberjar
  2. Schattiert. Wie nicht schattiert, jedoch alle Pakete aller Abhängigkeiten umbenennen (dh "Schatten").
    • Pro: Funktioniert mit dem Standard-Klassenladeprogramm von Java. Vermeidet einige (nicht alle) Konflikte mit Abhängigkeitsversionen.
    • Con: Dateien, die in mehreren JAR-Dateien mit demselben Pfad vorhanden sind (z. B. META-INF / services / javax.script.ScriptEngineFactory), überschreiben sich gegenseitig und führen zu fehlerhaftem Verhalten.
    • Tools: Maven Shade Plugin
  3. JAR of JARs. Die endgültige JAR-Datei enthält die anderen darin eingebetteten JAR-Dateien.
    • Pro: Vermeidet Konflikte mit Abhängigkeitsversionen. Alle Ressourcendateien bleiben erhalten.
    • Con: Muss einen speziellen "Bootstrap" -Klassenlader bündeln, damit Java Klassen aus den umschlossenen JAR-Dateien laden kann. Das Debuggen von Problemen mit dem Klassenladeprogramm wird komplexer.
    • Tools: Eclipse JAR File Exporter, One-JAR.
André Valenti
quelle
1
In Bezug auf Dienste ist das Shadow-Plugin nicht ganz richtig. Einer von ihnen dient zum Verketten von Inhalten von Dateien im META-INF/servicesVerzeichnis. Weitere Infos hier: maven.apache.org/plugins/maven-shade-plugin/examples/…
vitro
7
        <!-- Method 1 -->
        <!-- Copy dependency libraries jar files to a separated LIB folder -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <excludeTransitive>false</excludeTransitive> 
                <stripVersion>false</stripVersion>
            </configuration>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <!-- Add LIB folder to classPath -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>


        <!-- Method 2 -->
        <!-- Package all libraries classes into one runnable jar -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
              <execution>
                <phase>package</phase>
                <goals>
                  <goal>single</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
              <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
              </descriptorRefs>
            </configuration>
        </plugin>            
Leslie Li
quelle
4

Meine endgültige Lösung für Eclipse Luna und m2eclipse: Benutzerdefinierter Klassenladeprogramm (nur 5 Klassen herunterladen und zu Ihrem Projekt hinzufügen): http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org. eclipse.jdt.ui / jar% 20in% 20jar% 20loader / org / eclipse / jdt / internal / jarinjarloader / ; Dieser Classloader ist der beste Classloader mit einem Glas und sehr schnell.

<project.mainClass>org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader</project.mainClass> <project.realMainClass>my.Class</project.realMainClass>

Edit in JIJConstants "Rsrc-Class-Path" auf "Class-Path"
mvn sauber Abhängigkeit: copy-Abhängigkeiten Paket
ist ein Glas mit Abhängigkeiten in lib - Ordner mit einem dünnen Classloader erstellt

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.java</include>
                <include>**/*.properties</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*</include>
            </includes>
            <targetPath>META-INF/</targetPath>
        </resource>
        <resource>
            <directory>${project.build.directory}/dependency/</directory>
            <includes>
                <include>*.jar</include>
            </includes>
            <targetPath>lib/</targetPath>
        </resource>
    </resources>
<pluginManagement>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>${project.mainClass}</mainClass>
                            <classpathPrefix>lib/</classpathPrefix>
                        </manifest>

                        <manifestEntries>
                            <Rsrc-Main-Class>${project.realMainClass}  </Rsrc-Main-Class>
                            <Class-Path>./</Class-Path>
                        </manifestEntries>

                    </archive>
                </configuration>
            </plugin>
<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
Glaucio Southier
quelle
Das Maven-Dependency-Plugin <outputDirectory> funktioniert nicht. Schreiben Sie immer in den Ordner "Dependency"
Glaucio Southier,
Erstellen Sie ein Glas mit einem internen Ordner "Abhängigkeit", der Projektabhängigkeiten enthält, und legen Sie es auf MANIFEST.MF
Glaucio Southier
<resources> <resource> <directory> src / main / java </ directory> <includes> <include> ** / *. java </ include> <include> ** / *. properties </ include> </ include > </ resource> <resource> <directory> src / main / resources </ directory> <filtering> true </ filter> <includes> <include> ** / * </ include> </ include> <targetPath> META -INF / </ targetPath> </ resource> <resource> <directory> $ {project.build.directory} / dependency / </ directory> <includes> <include> * .jar </ include> </ include> < targetPath> lib / </ targetPath> </ resource> </ resources>
Glaucio Southier
1
Basierend auf dieser Antwort habe ich dieses Projekt erstellt. Sie sollten nichts außer der POM-Datei ändern müssen: github.com/raisercostin/jarinjarloader
raisercostin
1

Wenn Sie Maven beiseite legen, können Sie JAR-Bibliotheken in das Hauptglas einfügen, müssen jedoch Ihren eigenen Klassenladeprogramm verwenden.

Überprüfen Sie dieses Projekt: One-JAR- Linktext

medopal
quelle
Es gibt auch ein Maven-Plugin für One-JAR: onejar-maven-plugin.googlecode.com/svn/mavensite/usage.html
Thilo
0

Dieser Beitrag ist vielleicht etwas alt, aber ich hatte in letzter Zeit auch das gleiche Problem. Die erste von John Stauffer vorgeschlagene Lösung ist gut, aber ich hatte einige Probleme, als ich diesen Frühling arbeite. Die von mir verwendeten Abhängigkeitsgläser des Frühlings enthalten einige Eigenschaftendateien und XML-Schemadeklarationen, die dieselben Pfade und Namen haben. Obwohl diese Gläser aus denselben Versionen stammen, sind die Gläser mit Abhängigkeiten Maven-Ziel " diese Datei mit der zuletzt gefundenen Datei überschrieben.

Am Ende konnte die Anwendung nicht gestartet werden, da die Federgläser nicht die richtigen Eigenschaftendateien finden konnten. In diesem Fall hat die von Rop vorgeschlagene Lösung mein Problem gelöst.

Auch seitdem existiert das Spring-Boot-Projekt. Es hat eine sehr coole Möglichkeit, dieses Problem zu lösen, indem ein Maven-Ziel bereitgestellt wird, das das Paketziel überlastet und einen eigenen Klassenlader bereitstellt. Siehe Referenzhandbuch für Federstiefel

Francois Gergaud
quelle
0

Schauen Sie sich diese Antwort an:

Ich erstelle ein Installationsprogramm, das als Java-JAR-Datei ausgeführt wird und WAR- und JAR-Dateien an den entsprechenden Stellen im Installationsverzeichnis entpacken muss. Das Abhängigkeits-Plugin kann in der Paketphase mit dem Kopierziel verwendet werden. Es lädt alle Dateien im Maven-Repository (einschließlich WAR-Dateien) herunter und schreibt sie, wo immer Sie sie benötigen. Ich habe das Ausgabeverzeichnis in $ {project.build.directory} / classes geändert und das Endergebnis ist, dass die normale JAR-Aufgabe meine Dateien einwandfrei enthält. Ich kann sie dann extrahieren und in das Installationsverzeichnis schreiben.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
    <execution>
        <id>getWar</id>
        <phase>package</phase>
        <goals>
            <goal>copy</goal>
        </goals>
        <configuration>
            <artifactItems>
                <artifactItem>
                    <groupId>the.group.I.use</groupId>
                    <artifactId>MyServerServer</artifactId>
                    <version>${env.JAVA_SERVER_REL_VER}</version>
                    <type>war</type>
                    <destFileName>myWar.war</destFileName>
                </artifactItem>
            </artifactItems>
            <outputDirectory>${project.build.directory}/classes</outputDirectory>
        </configuration>
    </execution>
</executions>

Millebi
quelle
0

Vielen Dank, ich habe unten Snippet in POM.xml-Datei hinzugefügt und Mp-Problem behoben und erstellen Sie Fat JAR-Datei, die alle abhängigen Gläser enthält.

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>single</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <descriptorRefs>
                <descriptorRef>dependencies</descriptorRef>
            </descriptorRefs>
        </configuration>
    </plugin>
</plugins>
Rajeev Rathor
quelle