2012-08-01 3 views
77

Sto usando Maven nella mia applicazione stand-alone, e voglio confezionare tutte le dipendenze nel mio file JAR all'interno di una cartella di libreria, come accennato in una delle risposte qui:Come posso inserire tutti i file JAR richiesti in una cartella della libreria all'interno del file JAR finale con Maven?

How can I create an executable JAR with dependencies using Maven?

voglio il mio file JAR finale per avere una cartella della libreria che contiene le dipendenze come file JAR, non come quello che lo maven-shade-plugin mette le dipendenze sotto forma di cartelle come la gerarchia Maven nella cartella .m2.

Bene, in realtà la configurazione corrente fa quello che voglio, ma sto riscontrando un problema con il caricamento dei file JAR quando si esegue l'applicazione. Non riesco a caricare le classi.

Ecco la mia configurazione:

<plugins> 

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

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

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

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

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

</plugins> 

Il progetto funziona bene da Eclipse, ed i file JAR vengono inseriti nella cartella della libreria all'interno del mio file JAR finale come voglio, ma quando si esegue il file JAR finale da parte del cartella di destinazione ho sempre trovato ClassNotFoundException:

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext 
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext 
     at java.net.URLClassLoader$1.run(Unknown Source) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at java.net.URLClassLoader.findClass(Unknown Source) 
     at java.lang.ClassLoader.loadClass(Unknown Source) 
     at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) 
     at java.lang.ClassLoader.loadClass(Unknown Source) 
Could not find the main class: com.myapp.MainClass. Program will exit. 

Come posso risolvere questa eccezione?

+1

quale comando usi per avviare il barattolo? probabilmente potresti preferire il plugin exec di maven? –

+0

Il messaggio di eccezione non è aggiornato rispetto al file POM? Sembra che la classe principale 'com.myapp.MainClass' è stata cercata, non' com.tastycafe.MainClass'. –

+0

@Duncan Jones, problema di copia incolla, ho modificato la domanda –

risposta

0

Questo è chiaramente un problema di classpath. Tenere presente che il classpath deve cambiare leggermente quando si esegue il programma all'esterno dell'IDE. Questo perché l'IDE carica gli altri JAR relativi alla cartella radice del progetto, mentre nel caso del JAR finale questo di solito non è vero.

Quello che mi piace fare in queste situazioni è costruire manualmente il JAR. Ci metto al massimo 5 minuti e risolve sempre il problema. Non ti suggerisco di farlo. Trova un modo di usare Maven, questo è il suo scopo.

+0

cosa intendi per costruire manualmente il vaso? –

+0

@SoboLAN Costruire manualmente il JAR non è una soluzione. L'intenzione è di usare Maven, che è l'esatto opposto del "manuale"! –

+0

@DuncanJones Hai perfettamente ragione. Suggerisco che usi Maven per farlo. Tuttavia, non ho esperienza con esso e non sapevo esattamente quale soluzione raccomandare. Ho modificato la mia risposta per riflettere questo. –

21

Il più semplice e il modo più efficace è quello di utilizzare un plugin uber come questo:

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

Avrete de-normalizzato tutto in un unico file JAR.

+0

usarlo in aggiunta alla mia configurazione attuale? e cosa fa esattamente questo plugin? –

+13

Non voglio che il mio file jar assomigli a questo, voglio avere tutte le dipendenze in una cartella lib all'interno del file jar come fa netbean. –

3

Ecco come lo faccio:

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

E poi ho appena eseguito:

mvn assembly:assembly 
+1

non è quello che voglio, per favore leggi attentamente la domanda. –

+1

Nota che dovresti sempre fare una compilazione in anticipo perché 'assembly' metterà semplicemente tutto ciò che è in" target/classes "nel JAR. Ciò assicurerà che il JAR includa tutte le modifiche apportate di recente al codice sorgente. Quindi, dovresti fare qualcosa del tipo: 'mvn clean compile assembly: assembly'. – naXa

21

Aggiornato:

<build> 
    <plugins> 
    <plugin> 
    <artifactId>maven-dependency-plugin</artifactId> 
    <executions> 
     <execution> 
     <phase>install</phase> 
      <goals> 
      <goal>copy-dependencies</goal> 
      </goals> 
      <configuration> 
      <outputDirectory>${project.build.directory}/lib</outputDirectory> 
      </configuration> 
     </execution> 
     </executions> 
    </plugin> 
    </plugins> 
</build> 
+1

non è quello che voglio, per favore leggi attentamente la domanda –

+2

mette la cartella lib fuori dal barattolo (che non è quello che voglio). è meglio che mettere la lib all'interno del barattolo? e come consegnare l'applicazione al cliente in questo caso? –

+0

ora è più chiaro per me. fammi fare una ricerca su google. Ma mi piacerebbe sapere perché si desidera copiare tutto il file jar di dipendenza nella cartella specificata all'interno del file jar eseguibile. Se tutti i file jar di dipendenza sono all'interno del file jar, perché è necessario individuarli in una cartella lib? –

57

Quanto segue è la mia soluzione.Provatelo se funziona per voi:

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

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

Il primo plugin mette tutte le dipendenze nella cartella di destinazione/classes/lib, e la seconda include la cartella della libreria nel file JAR finale, e configura il file Manifest.mf.

Tuttavia, è necessario aggiungere codice di caricamento classi personalizzato per caricare i file JAR.

Oppure, per evitare classloading personalizzato, è possibile utilizzare "$ {} project.build.directory/lib, ma in questo caso, non si hanno le dipendenze all'interno del file JAR finale, che sconfigge lo scopo.

..

sono passati due anni da quando la domanda è stata posta il problema di file JAR annidati persiste tuttavia spero che aiuta qualcuno

+1

Uso: mvn install, cd target, java -jar MyJarFile-1.0.jar – djb

+0

Cool, questo funziona anche per cloudfoundry – Keymon

+0

cosa mi manca? Ciò crea una voce manifest classpath contenente "lib /" e tutto il singolo jar dalla cartella lib. È questo? Perché? – gapvision

1

ho trovato questa risposta alla domanda:.

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

Non solo ti prendi t a dipendenza dei file lib in una cartella lib, si ottiene anche un bin director con sia unix che un eseguibile dos.

L'eseguibile alla fine chiama java con un argomento -cp che elenca anche tutte le librerie dipendenti.

L'intero lotto si trova in una cartella di applicazioni all'interno della cartella di destinazione. Epico.

============= Sì. So che questo è un thread vecchio, ma sta ancora arrivando in alto nei risultati di ricerca quindi ho pensato che potesse aiutare qualcuno come me.

9

Il executable packer maven plugin può essere utilizzato esattamente per questo scopo: creazione di applicazioni Java standalone contenenti tutte le dipendenze come file JAR in una cartella specifica.

basta aggiungere quanto segue al pom.xml all'interno della sezione <build><plugins> (assicuratevi di sostituire il valore di mainClass di conseguenza):

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

Il file JAR costruzione, è situato a target/<YourProjectAndVersion>-pkg.jar dopo aver eseguito mvn package. Tutte le sue dipendenze in fase di compilazione e runtime saranno incluse nella cartella lib/ all'interno del file JAR.

Disclaimer: Sono l'autore del plug-in.

+0

Sarebbe bello cambiare il nome del jar di destinazione –

+0

L'ho provato e posso dire che funziona ... Come hai detto, questo plugin crea un file jar, con le sue librerie (jar) in una directory lib nel jar .. La configurazione è veramente semplice .. ** Penso che sia quello che l'autore di questa domanda si aspetta ** ... Ti darò il mio voto ... L'unico inconveniente che ho trovato su di esso (che s il perché non potrei usarlo), c'è un ritardo quando eseguo il mio barattolo e l'applicazione è mostrata (circa 20 secondi) probabilmente a causa del processo per registrare le librerie nel classloader personalizzato ... Ma è un ottimo approccio e un ottimo plugin ... –