Come posso creare un JAR eseguibile con dipendenze usando Maven?

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

Come posso creare un pacchetto di progetti Maven con tutti i JAR di dipendenza nel mio JAR di output?

   maven-assembly-plugin    fully.qualified.MainClass    jar-with-dependencies      

e tu lo gestisci con

 mvn clean compile assembly:single 

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

Vedi più dettagli nei commenti.


Comunemente questo objective è legato ad una fase di build da eseguire automaticamente. Ciò assicura che il JAR sia costruito quando si esegue mvn install o si esegue una distribuzione / rilascio.

  maven-assembly-plugin    fully.qualified.MainClass    jar-with-dependencies     make-assembly  package   single     

Puoi usare il plugin dependance per generare tutte le dipendenze in una directory separata prima della fase del pacchetto e quindi includerlo nel classpath del manifest:

  org.apache.maven.plugins maven-dependency-plugin   copy-dependencies prepare-package  copy-dependencies   ${project.build.directory}/lib false false true      org.apache.maven.plugins maven-jar-plugin    true lib/ theMainClass     

In alternativa, utilizzare ${project.build.directory}/classs/lib come OutputDirectory per integrare tutti i file jar nel jar principale, ma in tal caso sarà necessario aggiungere codice di caricamento ${project.build.directory}/classs/lib personalizzato per caricare i jar.

Ho bloggato su alcuni modi diversi per farlo.

Vedi Jar eseguibile con Apache Maven (WordPress)

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

Gli appunti

Questi pro e contro sono forniti da Stephan .


Per la distribuzione manuale

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

Copia le dipendenze in una directory specifica

  org.apache.maven.plugins maven-dependency-plugin   copy-dependencies prepare-package  copy-dependencies   ${project.build.directory}/${project.build.finalName}.lib     

Rendere eseguibile il jar e classpath consapevole

  org.apache.maven.plugins maven-jar-plugin    true ${project.build.finalName}.lib/ ${fully.qualified.main.class}     

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

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

Crea archivi deployabili

Il file jar è eseguibile solo con la directory ...lib/ sibling. Dobbiamo creare archivi da implementare con la directory e il suo contenuto.

  org.apache.maven.plugins maven-antrun-plugin   antrun-archive package  run                

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


Apache Maven Assembly Plugin

  • Professionisti
  • Contro
    • Nessun supporto per il trasferimento di class (usa maven-shade-plugin se è necessario il riposizionamento di class).
  org.apache.maven.plugins maven-assembly-plugin   package  single     ${fully.qualified.main.class}    jar-with-dependencies      

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


Apache Maven Shade Plugin

  • Professionisti
  • Contro
  org.apache.maven.plugins maven-shade-plugin    shade   true   ${fully.qualified.main.class}       

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


onejar-maven-plugin

  • Professionisti
  • Contro
    • Non supportato triggersmente dal 2012.
    com.jolira onejar-maven-plugin    ${fully.qualified.main.class} true  

Prendendo la risposta di Unanswered e riformattandola, abbiamo:

    org.apache.maven.plugins maven-jar-plugin    true fully.qualified.MainClass      maven-assembly-plugin   jar-with-dependencies      

Quindi, ti consiglio 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.xml e pom.xml all’evento del ciclo di vita del package . Tuttavia, un getcha è che è necessario chiamare l’ assembly:single objective se si inserisce questo nel tuo pom.xml, mentre si chiamerebbe ‘assembly: assembly’ se lo si esegue manualmente dalla riga di comando.

  [...]    maven-assembly-plugin    true fully.qualified.MainClass    jar-with-dependencies     make-my-jar-with-dependencies package  single     [...]  [...]   

Usa il plugin maven-shade per raggruppare tutte le dipendenze in un uber-jar. Può anche essere usato per build un jar eseguibile specificando la class principale. Dopo aver provato ad usare maven-assembly e maven-jar, ho trovato che questo plugin si adattava meglio alle mie esigenze.

Ho trovato questo plugin particolarmente utile in quanto unisce il contenuto di file specifici anziché sovrascriverli. Questo è necessario quando ci sono file di risorse che hanno lo stesso nome attraverso i jar e il plugin tenta di comprimere tutti i file di risorse

Vedi l’esempio qui sotto

     org.apache.maven.plugins maven-shade-plugin 1.4   package  shade      bouncycastle:bcprov-jdk15      com.main.MyMainClass    properties.properties   applicationContext.xml   META-INF/cxf/cxf.extension   META-INF/cxf/bus-extensions.xml        

Utilizzava a lungo il plugin di assembly maven , ma non sono riuscito a trovare una soluzione al problema con "already added, skipping" . Ora sto usando un altro plugin: onejar-maven-plugin . Esempio di seguito ( mvn package build jar):

  org.dstovall onejar-maven-plugin 1.3.0    com.company.MainClass   one-jar     

Devi aggiungere repository per quel plugin:

   onejar-maven-plugin.googlecode.com http://onejar-maven-plugin.googlecode.com/svn/mavenrepo   

Puoi usare maven-dependency-plugin, ma la domanda era come creare un JAR eseguibile. Per farlo è necessaria la seguente modifica alla risposta di Matthew Franglen (btw, usare il plugin di dipendenza richiede più tempo per essere compilato quando si parte da una destinazione pulita):

    maven-jar-plugin    fully.qualified.MainClass      maven-dependency-plugin   unpack-dependencies package  unpack-dependencies        ${basedir}/target/dependency    

Un’altra opzione se si desidera riconfezionare gli altri contenuti dei JAR all’interno del proprio JAR risultante è il plug-in Maven Assembly . Spacchetta e poi reimposta tutto in una directory tramite true . Poi avresti un secondo passaggio che lo ha costruito in un massiccio JAR.

Un’altra opzione è il plugin OneJar . Questo esegue le azioni di riconfezionamento di cui sopra in un unico passaggio.

Puoi aggiungere quanto segue al tuo pom.xml :

  install   maven-compiler-plugin 2.3.2  1.6 1.6    org.apache.maven.plugins maven-jar-plugin 2.3.1    true com.mycompany.package.MainClass      maven-assembly-plugin   jar-with-dependencies    com.mycompany.package.MainClass      make-my-jar-with-dependencies package  single       

Successivamente devi passare dalla console alla directory, dove si trova pom.xml. Quindi è necessario eseguire mvn assembly: single e quindi si spera che il file JAR eseguibile con dipendenze si sviluppi . Puoi controllarlo quando passi alla directory di output (target) con cd ./target e avvia 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 .

È ansible combinare il maven-shade-plugin maven-jar-plugin .

  • Il maven-shade-plugin racchiude le tue classi e tutte le dipendenze in un singolo file jar.
  • Configura il maven-jar-plugin di maven-jar-plugin per specificare la class principale del tuo jar eseguibile (consulta la sezione Impostazione del percorso di class, capitolo “Rendi eseguibile il jar”).

Esempio di configurazione POM per maven-jar-plugin :

   org.apache.maven.plugins maven-jar-plugin 2.3.2    true com.example.MyMainClass     

Infine crea il jar eseguibile richiamando:

 mvn clean package shade:shade 

Ho esaminato ognuna di queste risposte cercando di creare un grosso contenitore eseguibile contenente tutte le dipendenze e nessuno di questi ha funzionato correttamente. La risposta è il plugin per l’ombra, è molto semplice e diretto.

   org.apache.maven.plugins maven-shade-plugin 2.3    package  shade     path.to.MainClass       

Essere consapevoli del fatto che le proprie dipendenze devono avere un ambito di compilazione o runtime affinché funzioni correttamente.

Questo esempio è venuto da mkyong.com

Ken Liu ha ragione, secondo me. Il plug-in Maven dependency ti consente di espandere tutte le dipendenze, che puoi quindi considerare come risorse. Questo ti permette 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 è finito come:

  ...    org.apache.maven.plugins maven-dependency-plugin   unpack-dependencies package  unpack-dependencies      ...   ${basedir}/target/dependency /    ...  

Ecco un plugin jar eseguibile per Maven che usiamo su Credit Karma. Crea un barattolo di barattoli con un classloader in grado di caricare le classi dai jar annidati. Ciò consente di avere lo stesso classpath in dev e prod e mantenere comunque tutte le classi in un unico file jar firmato.

https://github.com/creditkarma/maven-exec-jar-plugin

Ed ecco un post sul blog con dettagli sul plugin e sul perché lo abbiamo realizzato: https://engineering.creditkarma.com/general-engineering/new-executable-jar-plugin-available-apache-maven/

Puoi usare il plugin maven-shade per build un bar uber come sotto

   org.apache.maven.plugins maven-shade-plugin   package  shade     

Usa il plugin unjar per costruirlo come un file jar eseguibile che racchiude tutti i barattoli dipendenti. Questo ha risolto il mio problema che era simile a questo. Quando è stato utilizzato il plug-in di assemblaggio, ha decompresso tutti i jar dipendenti nella cartella di origine e li ha riconfezionati come jar, aveva sovrascritto tutte le implementazioni simili che avevo nel mio codice che avevano gli stessi nomi di class. onejar è una soluzione facile qui.

Problema con l’individuazione del file assembly condiviso con maven-assembly-plugin-2.2.1?

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

Nessuno dei due fa quello che ti serve: cerca il file su classpath. Ovviamente è necessario aggiungere il pacchetto in cui risiede l’assembly condiviso sul classpath del maven-assembly-plugin (vedi sotto). Se stai usando Maven 2.x (non Maven 3.x), potresti aver bisogno di aggiungere questa dipendenza in pom.xml padre in cima alla sezione pluginManagement.

Vedi questo per maggiori dettagli.

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

Esempio:

    maven-assembly-plugin 2.2.1   make-assembly package  single   assembly-zip-for-wid      cz.ness.ct.ip.assemblies TEST_SharedAssemblyDescriptor 1.0.0-SNAPSHOT    

Dovrebbe essere così:

   maven-dependency-plugin   unpack-dependencies generate-resources  unpack-dependencies     

Il disimballaggio deve essere in fase di generazione delle risorse perché, se in fase di pacchetto, non sarà incluso come risorse. Prova pacchetto pulito e vedrai.

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

Vedo il punto (facilità di implementazione / utilizzo) ma dipende dal caso d’uso del tuo object (e potrebbero esserci alternative (vedi sotto)).

Se lo usi completamente standalone, perché no.

Ma se usi il tuo progetto in altri contesti (come in una webapp o in una cartella in cui sono presenti altri vasi), potresti avere dei duplicati di jar nel classpath (quelli nella cartella, quello nei barattoli). Forse non è un’offerta ma di solito evito questo.

Una buona alternativa:

  • distribuisci la tua applicazione come .zip / .war: l’archivio contiene il barattolo del tuo progetto e tutti i barattoli dipendenti;
  • usa un meccanismo dinamico per il classloader (vedi Spring, o puoi farlo tu da solo) per avere un singolo entry point del tuo progetto (una singola class da avviare – vedi il meccanismo Manifest su un’altra risposta), che aggiungerà (dynamicmente) al classpath corrente tutti gli altri vasi necessari.

In questo modo, con alla fine solo un manifest e un “main dynamic classloader main” speciale, puoi iniziare il tuo progetto con:

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

Se vuoi se dalla linea di comando stessa. Basta eseguire il comando sottostante dal percorso del progetto

MVN assemblaggio: assemblaggio

Puoi anche usare questo plug-in, è abbastanza buono e lo uso per confezionare i miei vasi http://sonatype.github.io/jarjar-maven-plugin/

Qualcosa che ha funzionato per me è stato:

   maven-dependency-plugin   unpack-dependencies prepare-package  unpack-dependencies   ${project.build.directory}/classs      org.apache.maven.plugins maven-jar-plugin   unpack-dependencies package      true lib/ SimpleKeyLogger     

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

  .. system ${project.basedir}/lib/myjar.jar  

Ho modificato il codice fornito da @ user189057 con le modifiche: 1) maven-dependency-plugin è eseguito in “prepar-package” fase 2) Sto estraendo le classw decompresse direttamente in “target / classs”

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

Avevo un requisito simile a quello dell’OP solo che avevo troppe dipendenze (Maven) per il mio progetto. Fortunatamente, l’unica soluzione che ha funzionato per me è stata l’utilizzo di Eclipse . Molto semplice e molto semplice. 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 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 class con il metodo Main che si desidera eseguire e scegliere le Package dependencies with the Jar file e fare clic su Finish

Questo è il modo migliore che ho trovato:

   org.apache.maven.plugins maven-jar-plugin 2.4    true com.myDomain.etc.MainClassName dependency-jars/      org.apache.maven.plugins maven-dependency-plugin 2.5.1   copy-dependencies package  copy-dependencies    ${project.build.directory}/dependency-jars/      

Con questa configurazione, tutte le dipendenze si troveranno in /dependency-jars . La mia applicazione non ha una class Main , solo una di contesto, ma una delle mie dipendenze ha una class Main ( com.myDomain.etc.MainClassName ) che avvia il server JMX e riceve un parametro start o stop . 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.

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

     org.apache.maven.plugins maven-assembly-plugin    true com.your.package.MainClass    jar-with-dependencies     make-my-jar-with-dependencies package  single        

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/

Il plugin maven-assembly ha funzionato alla grande per me. Ho passato ore con il plug-in maven-dependency e non sono riuscito a farlo funzionare. Il motivo principale era che dovevo definire esplicitamente nella sezione di configurazione gli elementi artefatti che dovrebbero essere inclusi come descritto nella documentazione . Esiste un esempio per i casi in cui si desidera utilizzarlo come: mvn dependency:copy , dove non sono inclusi gli oggetti artefatto ma non funziona.

Questa potrebbe anche essere un’opzione, sarai in grado di build il tuo file jar

     org.apache.maven.plugins maven-jar-plugin 2.4    true lib/ WordListDriver       

Ho confrontato i plugin dell’albero menzionati in questo post. Ho generato 2 barattoli e una directory con tutti i barattoli. Ho confrontato i risultati e sicuramente il plugin maven-shade è il migliore. La mia sfida era che avevo più risorse primaverili che dovevano essere unite, così come i servizi jax-rs e JDBC. Sono stati tutti uniti in modo corretto dal plugin di ombreggiatura in confronto con il plugin di maven-assembly. In tal caso, la molla fallirà a meno che non li copi nella tua cartella delle risorse personali e li unisca 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. They both produced the same manifest but I was able to consolidate licenses with the shade plugin using their transformsr. With the maven-dependency-plugin of course you don’t have those problems because the jars are not extracted. But like some other have pointed you need to carry one extra file(s) to work properly. Here is a snip of the pom.xml

   org.apache.maven.plugins maven-dependency-plugin   copy-dependencies prepare-package  copy-dependencies   ${project.build.directory}/lib compile true false false true      org.apache.maven.plugins maven-assembly-plugin 2.6    true com.rbccm.itf.cdd.poller.landingzone.LandingZonePoller    jar-with-dependencies     make-my-jar-with-dependencies package  single      org.apache.maven.plugins maven-shade-plugin 2.4.3  false false   META-INF/services/javax.ws.rs.ext.Providers   META-INF/spring.factories   META-INF/spring.handlers   META-INF/spring.schemas   META-INF/spring.tooling           shade     

For anyone looking for options to exclude specific dependencies from the uber-jar, this is a solution that worked for me:

    org.apache.spark spark-core_2.11 1.6.1 provided <=============      maven-assembly-plugin   jar-with-dependencies    ...      make-assembly package  single        

So it’s not a configuration of the mvn-assembly-plugin but a property of the dependency.

There are millions of answers already, I wanted to add you don’t need if you don’t need to add entryPoint to your application. For example APIs may not have necessarily have main method.

maven plugin config

   log-enrichment   maven-assembly-plugin   jar-with-dependencies      

build

 mvn clean compile assembly:single 

verify

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

Add to pom.xml:

   com.jolira onejar-maven-plugin 1.4.4  

e

  com.jolira onejar-maven-plugin 1.4.4    one-jar     

Thats it. Next mvn package will also create one fat jar additionally, including all dependency jars.