Incluse le dipendenze in un barattolo con Maven


353

C'è un modo per forzare Maven (2.0.9) per includere tutte le dipendenze in un singolo file jar?

Ho un progetto che costruisce in un singolo file jar. Voglio che anche le classi delle dipendenze vengano copiate nel vaso.

Aggiornamento: so che non posso semplicemente includere un file jar in un file jar. Sto cercando un modo per decomprimere i barattoli specificati come dipendenze e impacchettare i file di classe nel mio vaso.




2
Come includere un file jar nel file jar in Maven?
Kush Patel,

Risposte:


488

Puoi farlo usando il plugin maven-assembly con il descrittore "jar-with-dependencies". Ecco il pezzo rilevante di uno dei nostri pom.xml che fa questo:

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

30
L' attachedobiettivo è deprecato. L' obiettivo singleo directory-singledovrebbe essere preferito invece.
Pascal Thivent,

16
directory-singleora è anche deprecato.
James McMahon,

14
si consiglia di utilizzare single sul sito Web
mateuszb,

42
Nel caso in cui qualcuno nuovo di mvn fosse bloccato come me, aggiungi il plugin a <plugins> all'interno di <build> che si trova all'interno di <project>.
DA

10
@ Christian.tucker C'è un secondo vaso nella directory di destinazione creato in questo modo: ./target/example-0.0.1-SNAPSHOT.jar e ./target/example-0.0.1-SNAPSHOT-jar-with-dependencies.jar
tecnocrate

145

Con Maven 2, il modo giusto per farlo è usare il Plugin Assembly Maven2 che ha un file descrittore predefinito per questo scopo e che potresti semplicemente usare dalla riga di comando:

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

Se vuoi rendere eseguibile questo jar, aggiungi semplicemente la classe principale da eseguire alla configurazione del plugin:

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

Se si desidera creare quell'assemblaggio come parte del normale processo di compilazione, è necessario associare l' obiettivo singolo o singolo directory (l' assemblyobiettivo deve essere eseguito SOLO dalla riga di comando) a una fase del ciclo di vita ( packageha senso), qualcosa del genere:

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

Adatta l' configurationelemento in base alle tue esigenze (ad esempio con le cose manifest come dette).


Sto provando esattamente questo, tuttavia il plug-in non viene eseguito e il file jar non viene creato anche se la build viene eseguita senza problemi. C'è una trappola comune con cui potrei essermi bloccato?
posdef,

6
Funziona per me ma ho una quest. dopo build ora vengono creati due vasi uno con progetto artefactid-versione e un altro con artefactid-versione- "vaso-con-dipendenze". Ma voglio solo un barattolo da costruire. Esiste un altro modo
Souvik Bhattacharya,

38

Se si desidera eseguire un file jar eseguibile, è necessario impostare anche la classe principale. Quindi dovrebbe essere la configurazione completa.

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

2
Perché il nome di jar è aggiunto da "jar-with-dependencies" ?! Qualche soluzione alternativa?
Tina J,

1
@Tina J puoi aggiungere <appendAssemblyId>false</appendAssemblyId>all'interno del <configuration>tag per escludere il suffisso "-jar-with-dependencies" nel nome finale.
ccu


17

Puoi usare il vaso appena creato usando un <classifier>tag.

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

14

Se (come me) non ti piace in particolare l' approccio jar-with- dependments sopra descritto, la soluzione maven che preferisco è semplicemente costruire un progetto WAR, anche se si tratta solo di un'applicazione java autonoma che stai costruendo:

  1. Crea un normale progetto jar di Maven, che costruirà il tuo file jar (senza dipendenze).

  2. Inoltre, imposta un progetto di guerra maven (con solo un file src / main / webapp / WEB-INF / web.xml vuoto , che eviterà un avviso / errore nella build di maven), che ha solo il tuo progetto jar come una dipendenza, e rendi il tuo progetto jar una <module>sotto il tuo progetto di guerra. (Questo progetto di guerra è solo un semplice trucco per racchiudere tutte le dipendenze dei file jar in un file zip.)

  3. Costruisci il progetto di guerra per produrre il file di guerra.

  4. Nel passaggio di distribuzione, è sufficiente rinominare il file .war in * .zip e decomprimerlo.

Ora dovresti avere una directory lib (che puoi spostare dove vuoi) con il tuo jar e tutte le dipendenze di cui hai bisogno per eseguire la tua applicazione:

java -cp 'path/lib/*' MainClass

(Il carattere jolly in classpath funziona in Java-6 o versione successiva)

Penso che sia sia più semplice da installare in Maven (non c'è bisogno di scherzare con il plugin di assemblaggio) e ti dà anche una visione più chiara della struttura dell'applicazione (vedrai i numeri di versione di tutti i barattoli dipendenti in bella vista, e evitare di intasare tutto in un unico file jar).


È lo stesso di Eclipse "Esporta come vaso eseguibile"? Perché con questo puoi scegliere di "impacchettare tutte le dipendenze con il JAR", quindi ottieni tutte le dipendenze nella cartella project-lib, lungo il tuo vaso.
WesternGun

@FaithReaper - Potrebbe essere "lo stesso", non l'ho mai provato. Ma credo che se si utilizza Eclipse, non è facilmente tramite script, che è un requisito, se si desidera implementare un automatizzato di compilazione + deploy-pipeline. Ad esempio, lascia che Jenkins-server esegua la compilazione dal tuo repository di sorgenti git o simile.
Rop

12

http://fiji.sc/Uber-JAR fornisce un'eccellente spiegazione delle alternative:

Esistono tre metodi comuni per costruire un uber-JAR:

  1. Ombreggiata. Disimballare tutti i file JAR, quindi reimballarli in un singolo JAR.
    • Pro: funziona con il caricatore di classi predefinito di Java.
    • Contro: i file presenti in più file JAR con lo stesso percorso (ad es. META-INF / services / javax.script.ScriptEngineFactory) si sovrascriveranno a vicenda, causando comportamenti errati.
    • Strumenti: Maven Assembly Plugin, Classworlds Uberjar
  2. Ombreggiato. Lo stesso di non ombreggiato, ma rinomina (ovvero "ombra") tutti i pacchetti di tutte le dipendenze.
    • Pro: funziona con il caricatore di classi predefinito di Java. Evita alcuni (non tutti) scontri di versione di dipendenza.
    • Contro: i file presenti in più file JAR con lo stesso percorso (ad es. META-INF / services / javax.script.ScriptEngineFactory) si sovrascriveranno a vicenda, causando comportamenti errati.
    • Strumenti: Maven Shade Plugin
  3. VASO di VASI. Il file JAR finale contiene gli altri file JAR incorporati.
    • Pro: evita gli scontri della versione di dipendenza. Tutti i file di risorse vengono conservati.
    • Contro: deve raggruppare uno speciale caricatore di classi "bootstrap" per consentire a Java di caricare le classi dai file JAR avvolti. Il debug dei problemi del caricatore di classi diventa più complesso.
    • Strumenti: Eclipse JAR File Exporter, One-JAR.

1
Non del tutto vero per quanto riguarda i servizi, il plugin ombra ha trasformatori e uno di questi è per concatenare i contenuti dei file nella META-INF/servicesdirectory. Maggiori informazioni qui: 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>            

4

La mia soluzione definitiva su Eclipse Luna e m2eclipse: Classloader personalizzato (scarica e aggiungi al tuo progetto, solo 5 classi): http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org. eclipse.jdt.ui / jar% 20in% 20jar% 20loader / org / eclipse / jdt / internal / jarinjarloader / ; questo classloader è il migliore del classloader one-jar e molto veloce;

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

Modifica in JIJConstants "Rsrc-Class-Path" in "Class-Path"
mvn clean dependency: il pacchetto copy-dependencies
viene creato un vaso con dipendenze nella cartella lib con un thin classloader

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

il maven-dependency-plugin <outputDirectory> non funziona, scrivi sempre nella cartella "dependency"
Glaucio Southier

crea un vaso con una cartella "dipendenza" interna contenente le dipendenze del progetto e mettilo su 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 </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>
Glaucio Southier,

1
Sulla base di questa risposta ho creato questo progetto. Non dovresti aver bisogno di cambiare nulla tranne il file pom: github.com/raisercostin/jarinjarloader
raisercostin,


0

Questo post potrebbe essere un po 'vecchio, ma ho anche avuto lo stesso problema di recente. La prima soluzione proposta da John Stauffer è buona, ma ho avuto dei problemi mentre lavoro questa primavera. I barattoli di dipendenza della primavera che uso hanno alcuni file di proprietà e dichiarazioni di schemi xml che condividono gli stessi percorsi e nomi. Sebbene questi barattoli provengano dalle stesse versioni, il jar-with- dependments maven-goal stava sovrascrivendo il file di tesi con l'ultimo file trovato.

Alla fine, l'applicazione non è stata in grado di avviarsi poiché i barattoli di primavera non sono stati in grado di trovare i file delle proprietà corretti. In questo caso la soluzione proposta da Rop ha risolto il mio problema.

Inoltre da allora esiste ora il progetto di avvio a molla. Ha un ottimo modo per gestire questo problema fornendo un obiettivo maven che sovraccarica l'obiettivo del pacchetto e fornisce il proprio caricatore di classe. Vedere la Guida di riferimento degli stivali a molla


0

Dai un'occhiata a questa risposta:

Sto creando un programma di installazione che funziona come un file JAR Java e deve decomprimere i file WAR e JAR in posizioni appropriate nella directory di installazione. Il plug-in di dipendenza può essere utilizzato nella fase del pacchetto con l'obiettivo di copia e scaricherà qualsiasi file nel repository Maven (inclusi i file WAR) e li scriverà dove mai ne avrai bisogno. Ho cambiato la directory di output in $ {project.build.directory} / classes e quindi il risultato finale è che la normale attività JAR include i miei file bene. Posso quindi estrarli e scriverli nella directory di installazione.

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


0

Grazie ho aggiunto di seguito lo snippet nel file POM.xml e il problema Mp è stato risolto e ho creato il file jar jar che include tutti i barattoli dipendenti.

<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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.