Come posso creare un JAR eseguibile con dipendenze usando Maven?


2398

Voglio impacchettare il mio progetto in un unico JAR eseguibile per la distribuzione.

Come posso rendere un pacchetto di progetto Maven tutti i JAR di dipendenza nel mio JAR di output?


14
Spiegare quale obiettivo del plug-in di dipendenza si sta riferendo. Non conosco alcun obiettivo che faccia ciò che richiede la domanda originale: mettere tutte le dipendenze A) nel vaso degli autori tramite riconfezionamento, oppure B) creare un vaso eseguibile che abbia gli altri in un percorso di classe di MANIFEST.MF
Matthew McCullough

2
Potresti trovare questo utile rationaljava.com/2015/02/…
Dan,


Risposte:


2361
<build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>fully.qualified.MainClass</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </plugin>
  </plugins>
</build>

e lo esegui con

mvn clean compile assembly:single

L'obiettivo di compilazione deve essere aggiunto prima dell'assemblaggio: singolo o altrimenti il ​​codice sul proprio progetto non è incluso.

Vedi maggiori dettagli nei commenti.


Comunemente questo obiettivo è legato a una fase di costruzione per l'esecuzione automatica. Ciò garantisce che il JAR sia creato durante l'esecuzione mvn installo l'esecuzione di una distribuzione / rilascio.

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>fully.qualified.MainClass</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id> <!-- this is used for inheritance merges -->
      <phase>package</phase> <!-- bind to the packaging phase -->
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

22
Grazie @IAdapter. Nota che dovresti sempre fare una compilazione prima mano perché metterà tutto ciò che è in "target / classi" nel JAR. Ciò assicurerà che il JAR includa tutte le modifiche recentemente apportate al codice sorgente. Quindi, si dovrebbe fare qualcosa di simile: mvn clean compile assembly:single.
Michael,

10
Ho modificato la domanda per includere l'associazione di fase. Ho rimosso l'obiettivo dell'assemblaggio obsoleto, perché nessuno deve saperlo.
Duncan Jones,

2
Vedo che questo non aggiunge i vasetti al vaso Uber, invece aggiunge solo tutti i file di classe al vaso.
pitchblack408

170
Suggerimento: puoi anche aggiungere l'elemento <appendAssemblyId>false</appendAssemblyId>al configurationper evitare il fastidioso suffisso "-jar-with-dependencies" nel nome
maxivis,

6
dimentica compilee sei fregato.
prayagupd,

350

È possibile utilizzare il plug-in di dipendenza per generare tutte le dipendenze in una directory separata prima della fase del pacchetto e quindi includerlo nel percorso di classe del manifest:

<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}/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>theMainClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

In alternativa, utilizzare ${project.build.directory}/classes/libcome OutputDirectory per integrare tutti i file jar nel barattolo principale, ma sarà necessario aggiungere un codice di caricamento di classe personalizzato per caricare i barattoli.


3
+1 Eccellente. Il motivo per cui sto andando con maven-dependency-plugin invece di maven-assembly-plugin è che sto anche usando buildnumber-maven-plugin, e in questo modo posso memorizzare il numero di versione nel manifest di ogni vaso singolarmente.
PapaFreud,

17
Mi piace la tua soluzione. Uso ${project.build.directory}/classes/libcome outputDirectoryavere un .jar principale con tutte le dipendenze all'interno, ma - Come aggiungere un codice di caricamento di classe personalizzato per caricare questi vasi? Ho bisogno di fare esecuzione dei lavori come: java -jar main-jar-with-deps.jar. È possibile ?
Mario

3
@ André Aronsen, ho usato questa soluzione per aggiungere le dipendenze in una cartella lib all'interno del vaso, ma ottengo sempre un'eccezione di classe non trovata, puoi per favore consigliarti come risolverlo.
Mahmoud Saleh,

11
+1 a te !! Sembra che il plug-in di assemblaggio maven 'jar-with-dependencies' non funzioni davvero bene. Mi mancavano alcune voci di META-INF / spring.schemas nel vaso generato. Quindi ho eliminato il vaso con le dipendenze e ho usato la tua soluzione sopra. Perfetto grazie!!!
Derek,

9
Per chiunque abbia riscontrato questo problema, è necessario includere la cartella lib nella stessa directory con il proprio jar in cui si trasporta il jar.
Sparticles

224

Ho blog su alcuni modi diversi per farlo.

Vedi Jar eseguibile con Apache Maven (WordPress)

o eseguibile-jar-with-maven-example (GitHub)

Appunti

Quei pro e contro sono forniti da Stephan .


Per la distribuzione manuale

  • Professionisti
  • Contro
    • Le dipendenze sono fuori dal vaso finale.

Copia dipendenze in una directory specifica

<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}/${project.build.finalName}.lib</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

Rendi consapevole il vaso eseguibile e il percorso di classe

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

A questo punto jarè effettivamente eseguibile con elementi di classpath esterni.

$ java -jar target/${project.build.finalName}.jar

Crea archivi distribuibili

Il jarfile è eseguibile solo con la ...lib/directory dei fratelli . Dobbiamo creare archivi da distribuire con la directory e il suo contenuto.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>antrun-archive</id>
      <phase>package</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <target>
          <property name="final.name" value="${project.build.directory}/${project.build.finalName}"/>
          <property name="archive.includes" value="${project.build.finalName}.${project.packaging} ${project.build.finalName}.lib/*"/>
          <property name="tar.destfile" value="${final.name}.tar"/>
          <zip basedir="${project.build.directory}" destfile="${final.name}.zip" includes="${archive.includes}" />
          <tar basedir="${project.build.directory}" destfile="${tar.destfile}" includes="${archive.includes}" />
          <gzip src="${tar.destfile}" destfile="${tar.destfile}.gz" />
          <bzip2 src="${tar.destfile}" destfile="${tar.destfile}.bz2" />
        </target>
      </configuration>
    </execution>
  </executions>
</plugin>

Ora hai target/${project.build.finalName}.(zip|tar|tar.bz2|tar.gz)quale contiene ciascuno il jare lib/*.


Apache Maven Assembly Plugin

  • Professionisti
  • Contro
    • Nessun supporto per il trasferimento di classe (utilizzare maven-shade-plugin se è necessario il trasferimento di classe).
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <archive>
          <manifest>
            <mainClass>${fully.qualified.main.class}</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </execution>
  </executions>
</plugin>

Hai target/${project.bulid.finalName}-jar-with-dependencies.jar.


Apache Maven Shade Plugin

  • Professionisti
  • Contro
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>${fully.qualified.main.class}</mainClass>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

Hai target/${project.build.finalName}-shaded.jar.


onejar-Maven-plugin

  • Professionisti
  • Contro
    • Non attivamente supportato dal 2012.
<plugin>
  <!--groupId>org.dstovall</groupId--> <!-- not available on the central -->
  <groupId>com.jolira</groupId>
  <artifactId>onejar-maven-plugin</artifactId>
  <executions>
    <execution>
      <configuration>
        <mainClass>${fully.qualified.main.class}</mainClass>
        <attachToBuild>true</attachToBuild>
        <!-- https://code.google.com/p/onejar-maven-plugin/issues/detail?id=8 -->
        <!--classifier>onejar</classifier-->
        <filename>${project.build.finalName}-onejar.${project.packaging}</filename>
      </configuration>
      <goals>
        <goal>one-jar</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Spring Boot Maven Plugin

  • Professionisti
  • Contro
    • Aggiungi potenziali classi non necessarie relative a Spring e Spring Boot.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
      <configuration>
        <classifier>spring-boot</classifier>
        <mainClass>${fully.qualified.main.class}</mainClass>
      </configuration>
    </execution>
  </executions>
</plugin>

Hai target/${project.bulid.finalName}-spring-boot.jar.


2
@caiohamamura Puoi clonare il repository GitHub e vedere come funzionano tutti i profili.
Jin Kwon,

Il problema era con il pacchetto che stavo usando: stackoverflow.com/a/12622037/2548351
caiohamamura

1
Penso che questa sia probabilmente la risposta più completa a questo argomento.
Petr Bodnár,

139

Prendendo la risposta di Unanswered e riformattandola, abbiamo:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

Successivamente, consiglierei di renderlo una parte naturale della tua build, piuttosto che qualcosa da chiamare esplicitamente. Per renderlo parte integrante della tua build, aggiungi questo plugin al tuo pom.xmle packagecollegalo all'evento del ciclo di vita. Tuttavia, un gotcha è che devi chiamare l' assembly:singleobiettivo se lo metti nel tuo pom.xml, mentre chiameresti "assembly: assembly" se lo esegui manualmente dalla riga di comando.

<project>
  [...]
  <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <configuration>
                  <archive>
                      <manifest>
                          <addClasspath>true</addClasspath>
                          <mainClass>fully.qualified.MainClass</mainClass>
                      </manifest>
                  </archive>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
              </configuration>
              <executions>
                  <execution>
                      <id>make-my-jar-with-dependencies</id>
                      <phase>package</phase>
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      [...]
      </plugins>
    [...]
  </build>
</project>

10
L'uso dell'approccio in questa risposta genera il seguente messaggio di errore: "Impossibile caricare l'attributo manifest di classe principale da <file jar>", quando si tenta di eseguire il JAR usando "java -jar <file jar>"
Elmo

3
È necessaria una parte dell'archivio del plug-in maven-jar <archive> <manifest> <addClasspath> true </addClasspath> <mainClass> fully.qualified.MainClass </mainClass> </manifest> </archive>
Rade_303

4
Spiacenti, questa risposta è chiaramente errata, il tag mainClass deve trovarsi nella voce maven-assembly-plugin poiché lo stai chiamando durante l'obiettivo del pacchetto
Alex Lehmann,

Sono sorpreso, perché pom.xml non può già includerlo dopo l'archetipo mvn: generate command? È un po 'fastidioso copiarlo e incollarlo manualmente ogni volta che creo un nuovo progetto maven ...
Wintermute

non ho un metodo o classe principale, ho solo classe con funzione. come posso fare il barattolo e usarlo
parlad

97

Usa il plugin maven-shade per impacchettare tutte le dipendenze in un unico contenitore. Può anche essere usato per costruire un vaso eseguibile specificando la classe principale. Dopo aver provato a usare maven-assembly e maven-jar, ho scoperto che questo plugin si adattava meglio alle mie esigenze.

Ho trovato questo plugin particolarmente utile in quanto unisce il contenuto di file specifici invece di sovrascriverli. Ciò è necessario quando ci sono file di risorse che hanno lo stesso nome attraverso i barattoli e il plug-in tenta di impacchettare tutti i file di risorse

Vedi esempio sotto

      <plugins>
    <!-- This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <artifactSet>
                        <!-- signed jars-->
                            <excludes>
                                <exclude>bouncycastle:bcprov-jdk15</exclude>
                            </excludes>
                        </artifactSet>

                         <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- Main class -->
                                <mainClass>com.main.MyMainClass</mainClass>
                            </transformer>
                            <!-- Use resource transformers to prevent file overwrites -->
                            <transformer 
                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>properties.properties</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>applicationContext.xml</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/cxf/cxf.extension</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>META-INF/cxf/bus-extensions.xml</resource>
                            </transformer>
                     </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>

Quindi come fa bcprov-jdk15.jar a entrare nel percorso di classe in fase di esecuzione, dato che è escluso dal processo di shading?
Andrew Swan,

È stato attratto da cxf-rt-ws-security che fa parte delle mie dipendenze
Vijay Katam,

Non ho mai sentito parlare di questo plugin prima, ma ha risolto il mio problema con spring.handlers all'interno dei barattoli. Grazie!
Alexandre L Telles,

11
Coloro che hanno ottenuto un'eccezione di sicurezza, escludono i DSA dal Manifest. Controlla maven.apache.org/plugins/maven-shade-plugin/examples/…
ruhsuzbaykus

1 Ho usato minijar: ueberjar in passato, ma il plugin minijar è ora deprecato e sostituito da ombra
RDS

19

Ho usato a lungo il plugin di assemblaggio maven , ma non sono riuscito a trovare una soluzione al problema "already added, skipping". Ora sto usando un altro plugin - onejar-maven-plugin . Esempio di seguito ( mvn packagebuild jar):

<plugin>
    <groupId>org.dstovall</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <version>1.3.0</version>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.company.MainClass</mainClass>
            </configuration>
            <goals>
                <goal>one-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Devi aggiungere un repository per quel plugin:

<pluginRepositories>
    <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>

come sbarazzarsi di messaggi extra nell'output?
Alexandr

17

Puoi usare maven-dependency-plugin, ma la domanda era come creare un JAR eseguibile. Per fare ciò richiede la seguente modifica alla risposta di Matthew Franglen (tra l'altro, l'utilizzo del plug-in di dipendenza richiede più tempo per la creazione quando si parte da una destinazione pulita):

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>${basedir}/target/dependency</directory>
        </resource>
    </resources>
</build>

16

Puoi usare il plugin Maven-Shade per creare un vaso Uber come di seguito

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Ma allora come verrà distribuito al repository?
Francesco Gualazzi,

15

Un'altra opzione se si desidera veramente riconfezionare gli altri contenuti JAR all'interno del singolo JAR risultante è il plug-in Maven Assembly . Disimballa e quindi reimballa tutto in una directory tramite<unpack>true</unpack> . Quindi avresti un secondo passaggio che lo incorpora in un enorme JAR.

Un'altra opzione è il plug-in OneJar . Ciò esegue le azioni di riconfezionamento di cui sopra in un solo passaggio.


14

Puoi aggiungere quanto segue al tuo pom.xml :

<build>
<defaultGoal>install</defaultGoal>
<plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.3.1</version>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
    <executions>
      <execution>
        <id>make-my-jar-with-dependencies</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>
</build>

Successivamente è necessario passare dalla console alla directory, in cui si trova pom.xml. Quindi devi eseguire mvn assembly: single e quindi il tuo file JAR eseguibile con dipendenze sarà, si spera, compilato. Puoi controllarlo quando passi alla directory di output (target) con cd ./target e avvii il tuo jar con un comando simile a java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies.jar .

Ho provato questo con Apache Maven 3.0.3 .


13

Ho esaminato ognuna di queste risposte cercando di creare un grosso vaso eseguibile contenente tutte le dipendenze e nessuna di esse ha funzionato correttamente. La risposta è il plugin ombra, è molto semplice e diretto.

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>2.3</version>
      <executions>
         <!-- Run shade goal on package phase -->
        <execution>
        <phase>package</phase>
        <goals>
            <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
             <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>path.to.MainClass</mainClass>
             </transformer>
          </transformers>
        </configuration>
          </execution>
      </executions>
    </plugin>

Tieni presente che le tue dipendenze devono avere un ambito di compilazione o runtime per funzionare correttamente.

Questo esempio proviene da mkyong.com


Mentre ho risolto questo problema, ti dispiacerebbe aggiornare la tua recensione. Non avevo preso in considerazione i tuoi pensieri prima di pubblicare e ho rapidamente risolto il problema dopo aver visto il tuo commento
dsutherland

2
L' pluginelemento entra in pom.xmlunder build/plugins.
Isapir,

12

Potresti combinare il maven-shade-plugin e maven-jar-plugin.

  • Il maven-shade-pluginconfezioni classi e tutte le dipendenze in un unico file jar.
  • Configura maven-jar-pluginper specificare la classe principale del tuo vaso eseguibile (vedi Set Up classpath , capitolo "Make The Jar eseguibile").

Esempio di configurazione POM per maven-jar-plugin :

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.example.MyMainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

Infine, crea il vaso eseguibile invocando:

mvn clean package shade:shade

3
Il plugin Shade ora ha i mezzi per specificare la voce della classe principale nel manifest: maven.apache.org/plugins/maven-shade-plugin/examples/…
Chadwick

9

Secondo me Ken Liu ha ragione. Il plug-in di dipendenza Maven ti consente di espandere tutte le dipendenze, che puoi quindi trattare come risorse. Ciò consente di includerli nel manufatto principale . L'uso del plugin assembly crea un artefatto secondario che può essere difficile da modificare - nel mio caso volevo aggiungere voci manifest personalizzate. Il mio pom finì come:

<project>
 ...
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
     <execution>
      <id>unpack-dependencies</id>
      <phase>package</phase>
      <goals>
       <goal>unpack-dependencies</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
  </plugins>
  ...
  <resources>
   <resource>
    <directory>${basedir}/target/dependency</directory>
    <targetPath>/</targetPath>
   </resource>
  </resources>
 </build>
 ...
</project>

1
Veramente bello! Non sarebbe meglio usare la fase di generazione delle risorse per il disimballaggio?
nawroth,

9

Dovrebbe essere così:

<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>unpack-dependencies</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>unpack-dependencies</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Il disimballaggio deve essere in fase di generazione delle risorse perché, se in fase di pacchetto, non verrà incluso tra le risorse. Prova un pacchetto pulito e vedrai.


7

Problemi con l'individuazione del file assembly condiviso con maven-assembly-plugin-2.2.1?

Prova a utilizzare il parametro di configurazione descrittoreId invece dei parametri descrittori / descrittore o descriptorRefs / descriptorRef.

Nessuno dei due fa ciò di cui hai bisogno: cerca il file su classpath. Naturalmente è necessario aggiungere il pacchetto in cui si trova l'assembly condiviso sul percorso di classe di maven-assembly-plugin (vedere sotto). Se stai usando Maven 2.x (non Maven 3.x), potresti aver bisogno di aggiungere questa dipendenza in pom.xml principale nella sezione pluginManagement.

Vedi questo per maggiori dettagli.

Classe: org.apache.maven.plugin.assembly.io.DefaultAssemblyReader

Esempio:

        <!-- Use the assembly plugin to create a zip file of all our dependencies. -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <descriptorId>assembly-zip-for-wid</descriptorId>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>cz.ness.ct.ip.assemblies</groupId>
                    <artifactId>TEST_SharedAssemblyDescriptor</artifactId>
                    <version>1.0.0-SNAPSHOT</version>
                </dependency>
            </dependencies>
        </plugin>

7

Per risolvere questo problema utilizzeremo il plugin Maven Assembly che creerà il JAR insieme ai JAR di dipendenza in un singolo file JAR eseguibile. Aggiungi qui sotto la configurazione del plugin nel tuo file pom.xml.

<build>
   <pluginManagement>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
               <archive>
                  <manifest>
                     <addClasspath>true</addClasspath>
                     <mainClass>com.your.package.MainClass</mainClass>
                  </manifest>
               </archive>
               <descriptorRefs>
                  <descriptorRef>jar-with-dependencies</descriptorRef>
               </descriptorRefs>
            </configuration>
            <executions>
               <execution>
                  <id>make-my-jar-with-dependencies</id>
                  <phase>package</phase>
                  <goals>
                     <goal>single</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </pluginManagement>
</build>

Dopo aver fatto ciò, non dimenticare di eseguire lo strumento MAVEN con questo comando mvn clean compile assembly: single

http://jkoder.com/maven-creating-a-jar-together-with-its-dependency-jars-into-a-single-executable-jar-file/


5

Non risponderò direttamente alla domanda poiché altri l'hanno già fatto prima, ma mi chiedo davvero se sia una buona idea incorporare tutte le dipendenze nel vaso stesso del progetto.

Vedo il punto (facilità di distribuzione / utilizzo) ma dipende dal caso d'uso del tuo progetto (e potrebbero esserci delle alternative (vedi sotto)).

Se lo usi completamente autonomamente, perché no.

Ma se usi il tuo progetto in altri contesti (come in una webapp, o lasciato cadere in una cartella in cui si trovano altri vasetti), potresti avere dei duplicati nel tuo percorso di classe (quelli nella cartella, quello nei vasetti). Forse non è un'offerta, ma di solito evito questo.

Una buona alternativa:

  • distribuire l'applicazione come .zip / .war: l'archivio contiene il vaso del progetto e tutti i barattoli dipendenti;
  • usa un meccanismo dinamico di caricamento classi (vedi Spring, o puoi farlo facilmente da solo) per avere un singolo punto di ingresso del tuo progetto (una singola classe per iniziare - vedi il meccanismo Manifest su un'altra risposta), che si aggiungerà (dinamicamente) al percorso di classe corrente tutti gli altri vasi necessari.

In questo modo, con alla fine solo un manifest e uno "mainloader dinamico di classi speciali", puoi iniziare il tuo progetto con:

java -jar ProjectMainJar.jar com.stackoverflow.projectName.MainDynamicClassLoaderClass

1
Come mettere quindi il barattolo del progetto e tutti i barattoli dipendenti in un archivio?

4

Per creare un JAR eseguibile dalla stessa riga di comando, basta eseguire il comando seguente dal percorso del progetto:

mvn assembly:assembly

3
Penso che devi ancora fare alcune cose in caso pom.xmlcontrario Error reading assemblies: No assembly descriptors found.. Questo è quello che succede comunque per me.
Sridhar Sarnobat,

3

Questo è il modo migliore che ho trovato:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.4</version>
    <configuration>
      <archive>
        <manifest>
        <addClasspath>true</addClasspath>
        <mainClass>com.myDomain.etc.MainClassName</mainClass>
        <classpathPrefix>dependency-jars/</classpathPrefix>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
      <execution>
        <id>copy-dependencies</id>
        <phase>package</phase>
        <goals>
            <goal>copy-dependencies</goal>
        </goals>
        <configuration>
            <outputDirectory>
               ${project.build.directory}/dependency-jars/
            </outputDirectory>
        </configuration>
      </execution>
    </executions>
  </plugin>

Con questa configurazione, tutte le dipendenze saranno localizzate in /dependency-jars. La mia applicazione non ha Mainclasse, ma solo quelle di contesto, ma una delle mie dipendenze ha una Mainclasse ( com.myDomain.etc.MainClassName) che avvia il server JMX e riceve startun stopparametro o . Quindi con questo sono stato in grado di avviare la mia applicazione in questo modo:

java -jar ./lib/TestApp-1.0-SNAPSHOT.jar start

Aspetto che sia utile per tutti voi.


3

Ho confrontato i plugin dell'albero menzionati in questo post. Ho generato 2 vasetti e una directory con tutti i vasetti. Ho confrontato i risultati e sicuramente il plug-in maven-shade è il migliore. La mia sfida era che avevo più risorse di primavera che dovevano essere unite, così come jax-rs e servizi JDBC. Furono tutti uniti correttamente dal plugin ombra rispetto al plugin maven-assembly. Nel qual caso la primavera fallirà se non le copi nella tua cartella delle risorse e le unisci manualmente una volta. Entrambi i plugin producono l'albero delle dipendenze corretto. Ho avuto più ambiti come test, fornire, compilare, ecc. Il test e fornito sono stati saltati da entrambi i plugin. Entrambi hanno prodotto lo stesso manifest ma sono stato in grado di consolidare le licenze con il plug-in ombra utilizzando il loro trasformatore. Con il plugin maven-dependency ovviamente non Non hanno questi problemi perché i vasetti non vengono estratti. Ma come alcuni altri hanno sottolineato, è necessario trasportare un file extra per funzionare correttamente. Ecco un ritaglio di pom.xml

            <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}/lib</outputDirectory>
                        <includeScope>compile</includeScope>
                        <excludeTransitive>true</excludeTransitive>
                        <overWriteReleases>false</overWriteReleases>
                        <overWriteSnapshots>false</overWriteSnapshots>
                        <overWriteIfNewer>true</overWriteIfNewer>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.rbccm.itf.cdd.poller.landingzone.LandingZonePoller</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-my-jar-with-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <configuration>
                <shadedArtifactAttached>false</shadedArtifactAttached>
                <keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/services/javax.ws.rs.ext.Providers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.factories</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.handlers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.schemas</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.tooling</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer">
                    </transformer>
                </transformers>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

2

Qualcosa che ha funzionato per me è stato:

  <plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>prepare-package</phase>
        <goals>
          <goal>unpack-dependencies</goal>
        </goals>
        <configuration>
          <outputDirectory>${project.build.directory}/classes</outputDirectory>
        </configuration>
      </execution>

    </executions>
  </plugin>


  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>package</phase>
      </execution>
    </executions>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <classpathPrefix>lib/</classpathPrefix>
          <mainClass>SimpleKeyLogger</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>

Ho avuto un caso straordinario perché la mia dipendenza era il sistema uno:

<dependency>
  ..
  <scope>system</scope>
  <systemPath>${project.basedir}/lib/myjar.jar</systemPath>
</dependency>

Ho modificato il codice fornito da @ user189057 con le modifiche: 1) maven-dependency-plugin viene eseguito nella fase 2 di "ready-package") Sto estraendo classess decompressi direttamente in "target / classi"


2

Ho provato qui la risposta più votata e sono riuscito a far funzionare il vaso. Ma il programma non è stato eseguito correttamente. Non so quale fosse il motivo. Quando provo a scappareEclipse , ottengo un risultato diverso ma quando eseguo il jar dalla riga di comando ottengo un risultato diverso (si blocca con un errore di runtime specifico del programma).

Avevo un requisito simile al PO, solo che avevo troppe dipendenze (Maven) per il mio progetto. Fortunatamente, l'unica soluzione che ha funzionato per me è stata quella di utilizzare Eclipse. Molto semplice e molto diretto. Questa non è una soluzione all'OP ma è una soluzione per qualcuno che ha un requisito simile ma con molte dipendenze Maven,

1) Basta fare clic con il tasto destro sulla cartella del progetto (in Eclipse) e selezionare Export

2) Quindi selezionare Java->Runnable Jar

3) Ti verrà chiesto di scegliere la posizione del file jar

4) Infine, selezionare la classe che ha il metodo principale che si desidera eseguire e scegliere Package dependencies with the Jar filee fare clicFinish


2

Questa potrebbe anche essere un'opzione, sarai in grado di creare il tuo file jar

<build>
    <plugins>
        <plugin>
            <!-- Build an executable JAR -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>WordListDriver</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

2

Per chiunque cerchi opzioni per escludere dipendenze specifiche da Uber-Jar, questa è una soluzione che ha funzionato per me:

<project...>
<dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>1.6.1</version>
            <scope>provided</scope> <=============
        </dependency>
</dependencies>
<build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>...</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Quindi non è una configurazione del plugin mvn-assembly ma una proprietà della dipendenza.


2

Ci sono già milioni di risposte, volevo aggiungere che non è necessario <mainClass>se non è necessario aggiungere entryPoint alla propria applicazione. Ad esempio, le API potrebbero non avere necessariamente un mainmetodo.

maven plugin config

  <build>
    <finalName>log-enrichment</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>

costruire

mvn clean compile assembly:single

verificare

ll target/
total 35100
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ./
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ../
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 archive-tmp/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 classes/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-sources/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-test-sources/
-rwxrwx--- 1 root vboxsf 35929841 Sep 29 16:10 log-enrichment-jar-with-dependencies.jar*
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 maven-status/

2

Aggiungi a pom.xml:

  <dependency>
            <groupId>com.jolira</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
            <version>1.4.4</version>
  </dependency>

e

<plugin>
       <groupId>com.jolira</groupId>
       <artifactId>onejar-maven-plugin</artifactId>
       <version>1.4.4</version>
       <executions>
              <execution>
                     <goals>
                         <goal>one-jar</goal>
                     </goals>
              </execution>
       </executions>
</plugin>

Questo è tutto. Il prossimo pacchetto mvn creerà anche un vaso grasso in più, compresi tutti i vasetti di dipendenza.


1

Il plugin maven-assembly ha funzionato benissimo per me. Ho trascorso ore con il plugin maven-dependency e non sono riuscito a farlo funzionare. Il motivo principale era che dovevo definire esplicitamente nella sezione di configurazione gli elementi del manufatto che dovrebbero essere inclusi come descritto nella documentazione . C'è un esempio lì per i casi in cui vuoi usarlo come:, mvn dependency:copydove non sono inclusi oggetti artefatto ma non funziona.


1

Questo post sul blog mostra un altro approccio con la combinazione dei plugin maven-jar e maven-assembly. Con la configurazione dell'assembly xml dal post del blog, può anche essere controllato se le dipendenze verranno espanse o semplicemente raccolte in una cartella e referenziate da una voce del percorso di classe nel manifest:

La soluzione ideale è includere i barattoli in una cartella lib e il file manifest.mf del barattolo principale include tutti i barattoli nel percorso di classe.

Ed esattamente quello è descritto qui: https://caffebig.wordpress.com/2013/04/05/executable-jar-file-with-dependent-jars-using-maven/


0
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <!-- get all project dependencies -->
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!-- bind to the packaging phase -->
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

1
Ho bisogno di qualche spiegazione in più su questo; quei commenti sono solo documentazione o devono essere posizionate opzioni aggiuntive nelle posizioni di tali commenti?
Mark Stewart,

-2

Ok, quindi questa è la mia soluzione. So che non sta usando il file pom.xml. Ma ho avuto il problema durante la compilazione e l'esecuzione del mio programma su Netbeans ma non è riuscito quando ho provato Java -jar MyJarFile.jar. Ora, non capisco pienamente Maven e penso che questo abbia avuto problemi a far sì che Netbeans 8.0.2 includesse il mio file jar in una libreria per metterli in un file jar. Stavo pensando a come usavo i file jar senza Maven in Eclipse.

È Maven che può compilare tutte le dipendenze e i plugin. Non Netbeans. (Se puoi ottenere Netbeans ed essere in grado di usare java .jar per farlo, dimmi come (^. ^) V)

[Risolto - per Linux] aprendo un terminale.

Poi

cd /MyRootDirectoryForMyProject

Il prossimo

mvn org.apache.maven.plugins:maven-compiler-plugin:compile

Il prossimo

mvn install

Questo creerà il file jar nella directory di destinazione.

MyJarFile-1.0-jar-with-dependencies.jar

Adesso

cd target

(Potrebbe essere necessario eseguire chmod +x MyJarFile-1.0-jar-with-dependencies.jar:)

E infine

java -jar MyJarFile-1.0-jar-with-dependencies.jar

Perfavore guarda

https://cwiki.apache.org/confluence/display/MAVEN/LifecyclePhaseNotFoundException

Pubblicherò questa soluzione su un paio di altre pagine con un problema simile. Spero di poter salvare qualcuno da una settimana di frustrazione.


2
Prova ad aprire il progetto Maven che hai creato con Netbeans. La regola di base di Netbeans è sempre quella di creare un progetto Maven e mai una "applicazione Java". Aggiungete un plug-in maven-shade come una delle risposte. Funziona come un fascino.
rjdkolb,
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.