Come inserisco tutti i file JAR richiesti in una cartella della libreria all'interno del file JAR finale con Maven?


104

Sto usando Maven nella mia applicazione standalone e voglio impacchettare tutte le dipendenze nel mio file JAR all'interno di una cartella di libreria, come menzionato in una delle risposte qui:

Come posso creare un JAR eseguibile con dipendenze utilizzando Maven?

Voglio che il mio file JAR finale abbia una cartella di libreria che contenga le dipendenze come file JAR, non come ciò maven-shade-pluginche mette le dipendenze sotto forma di cartelle come la gerarchia di Maven nella cartella .m2.

Bene, in realtà la configurazione corrente fa quello che voglio, ma ho un problema con il caricamento dei file JAR durante l'esecuzione dell'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 correttamente da Eclipse ei file JAR vengono inseriti nella cartella della libreria all'interno del mio file JAR finale come desidero, ma quando eseguo il file JAR finale dalla cartella di destinazione ottengo sempre 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 correggere questa eccezione?


1
quale comando usi per eseguire il jar? probabilmente potresti preferire il plug-in esecutivo di Maven?
Andrey Borisov

Il messaggio di eccezione non è aggiornato rispetto al file POM? Sembra che com.myapp.MainClasssi stia cercando la classe principale , no com.tastycafe.MainClass.
Duncan Jones

@ Duncan Jones, problema copia incolla, ho modificato la domanda
Mahmoud Saleh

3
Nota che se vuoi jars all'interno del jar, i classloader standard in Java non possono capirli.
Thorbjørn Ravn Andersen

Come farlo posizionare le dipendenze Maven in una cartella lib ma fuori dal JAR?
ed22

Risposte:


81

La seguente è la mia soluzione. Provalo se funziona per te:

<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 inserisce tutte le dipendenze nella cartella target / classes / lib, e il secondo include la cartella della libreria nel file JAR finale e configura il Manifest.mffile.

Ma poi sarà necessario aggiungere codice di caricamento classi personalizzato per caricare i file JAR.

Oppure, per evitare il caricamento di classi personalizzato, puoi usare "$ {project.build.directory} / lib, ma in questo caso, non hai dipendenze all'interno del file JAR finale, il che vanifica lo scopo.

Sono passati due anni da quando è stata posta la domanda. Il problema dei file JAR nidificati persiste tuttavia. Spero che aiuti qualcuno.


1
Utilizzo: installazione mvn, destinazione cd, java -jar MyJarFile-1.0.jar
djb

cosa mi manca? Questo crea una voce del percorso di classe manifest contenente "lib /" e tutti i singoli jar dalla cartella lib. È inteso? Perché?
gapvision

2
Ha funzionato dopo che ho cambiato "$ {project.build.directory} / classes / lib" in $ {project.build.directory} / lib
Rajendra Thorat

1
Sfortunatamente include le dipendenze dichiarate come fornite.
Philippe Gioseffi

@Rajendra grazie, che mi ha aiutato: $ {project.build.directory} / lib
Mindaugas K.

30

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> 

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

ora è più chiaro per me. fammi fare una ricerca su Google. Ma vorrei sapere perché si desidera copiare tutto il file jar delle dipendenze nella cartella specificata all'interno del file jar eseguibile. Se tutti i file jar delle dipendenze si trovano all'interno del file jar, perché è necessario individuarli in una cartella lib?
Ahmet Karakaya

23

Il modo più semplice ed efficiente è usare 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>

Avrai de-normalizzato tutto in un file JAR.


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

15
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.
Mahmoud Saleh

12

Il plug-in Maven del packer eseguibile può essere utilizzato esattamente per questo scopo: creare applicazioni Java autonome contenenti tutte le dipendenze come file JAR in una cartella specifica.

Aggiungi semplicemente quanto segue pom.xmlall'interno della <build><plugins>sezione (assicurati di sostituire il valore di di mainClassconseguenza):

<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 creato si trova in target/<YourProjectAndVersion>-pkg.jardopo l'esecuzione mvn package. Tutte le sue dipendenze in fase di compilazione e runtime verranno incluse nella lib/cartella all'interno del file JAR.

Disclaimer: sono l'autore del plugin.


L'ho provato e posso dire che funziona ... Come hai detto, questo plugin crea un file jar, con le sue librerie (jars) in una directory lib nel jar ... La configurazione è davvero semplice .. Penso che sia quello l'autore di questa domanda si aspetta ... ti do il mio voto ... L'unico inconveniente che ho trovato su di esso (è il motivo per cui non ho potuto usarlo), c'è un ritardo quando eseguo il mio jar e l'applicazione viene mostrata (circa 20 secondi) probabilmente a causa del processo di registrazione delle librerie nel classloader personalizzato ... Ma è un ottimo approccio e un ottimo plugin ...
Adam M. Gamboa G.


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

mvn assembly:assembly

1
Nota che dovresti sempre fare una compilazione in anticipo perché assemblymetterà semplicemente tutto ciò che è in "target / classes" nel JAR. Ciò garantirà che il JAR includa tutte le modifiche apportate di recente al codice sorgente. Quindi, si dovrebbe fare qualcosa di simile: mvn clean compile assembly:assembly.
naXa

2

Ho trovato questa risposta alla domanda:

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

Non solo ottieni i file lib dipendenti in una cartella lib, ma ottieni anche un bin director con un eseguibile unix e dos.

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

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

============= Sì, lo so che questo è un vecchio thread, ma sta ancora arrivando in cima ai risultati di ricerca, quindi ho pensato che potesse aiutare qualcuno come me.


1

Questo è chiaramente un problema di classpath. Considera che il classpath deve cambiare un po 'quando esegui il tuo programma fuori dall'IDE. Questo perché l'IDE carica gli altri JAR relativi alla cartella principale del tuo progetto, mentre nel caso del JAR finale questo di solito non è vero.

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


@SoboLAN La creazione manuale del JAR non è una soluzione qui. L'intenzione è quella di utilizzare Maven, che è l'esatto opposto di "manual"!
Duncan Jones

@DuncanJones Hai assolutamente 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.
Radu Murzea
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.