Creazione di JAR eseguibile con Gradle


148

Fino ad ora ho creato file JAR eseguibili tramite la funzionalità "Esporta ..." di Eclipse, ma ora sono passato a IntelliJ IDEA e Gradle per l'automazione della compilazione.

Alcuni articoli qui suggeriscono il plug-in "application", ma questo non porta interamente al risultato che mi aspettavo (solo un JAR, nessun script di avvio o qualcosa del genere).

Come posso ottenere lo stesso risultato che Eclipse fa con la finestra di dialogo "Esporta ..."?

Risposte:


164

Un file jar eseguibile è solo un file jar che contiene una voce di classe principale nel suo manifest. Quindi devi solo configurare l' attività jar per aggiungere questa voce nel suo manifest:

jar {
    manifest {
        attributes 'Main-Class': 'com.foo.bar.MainClass'
    }
}

Potrebbe anche essere necessario aggiungere voci del percorso di classe nel manifest, ma ciò avverrebbe allo stesso modo.

Vedi http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html


6
Questo sembra essere quello che stavo cercando; ma: ho già dichiarato dipendenze in build.gradle, devo davvero aggiungere manualmente il percorso della classe o posso riutilizzare la mia dichiarazione di dipendenza?
Hannes,

Dovresti essere in grado di scorrere le librerie all'interno della configurazione 'runtime' e concatenarle per creare il valore dell'attributo Class-Path.
JB Nizet,

3
Cosa intendi con 'inseid la configurazione "runtime"? Scusami per le domande stupide, sono abbastanza nuovo per Gradle ...
Hannes,

Il plug-in java gradle definisce 4 "configurazioni" corrispondenti a 4 diversi percorsi di classe: compilazione (utilizzata per compilare i file Java), testCompile (che viene utilizzato per compilare i file di origine Java di prova), runtime (utilizzato per eseguire l'applicazione) e testRuntime (che viene utilizzato per eseguire i test). Vedi gradle.org/docs/current/userguide/…
JB Nizet,

Ah, grazie - di quanto ho capito bene e riesco a costruire il JAR, ora sto agitando la creazione del percorso di classe ;-) Grazie mille per il tuo aiuto!
Hannes,

98

Le risposte di JB Nizet e Jorge_B sono corrette.

Nella sua forma più semplice, la creazione di un JAR eseguibile con Gradle è solo una questione di aggiunta delle voci appropriate al manifest . Tuttavia, è molto più comune avere dipendenze che devono essere incluse nel percorso di classe, rendendo pratico questo approccio nella pratica.

Il plugin dell'applicazione fornisce un approccio alternativo; invece di creare un JAR eseguibile, fornisce:

  • un runcompito di facilitare facilmente funzionante l'applicazione direttamente dalla generazione
  • un installDistcompito che genera una struttura di directory incluso il JAR costruita, tutti i JAR che dipende, e uno script di avvio che tira tutto insieme in un programma è possibile eseguire
  • distZipe distTarattività che creano archivi contenenti una distribuzione completa dell'applicazione (script di avvio e JAR)

Un terzo approccio è quello di creare un cosiddetto "JAR grasso" che è un JAR eseguibile che include non solo il codice del componente, ma anche tutte le sue dipendenze. Esistono diversi plugin che utilizzano questo approccio. Ho incluso collegamenti ad alcuni di cui sono a conoscenza; Sono sicuro che ce ne sono altri.


Ho appena provato shadow e one-jar. Mi limiterò a un barattolo: è più semplice e più facile da usare. Freddo! grazie
Jako,

Sfortunatamente one-jar non funziona con le versioni recenti di Gradle. Vedi, ad esempio, github.com/rholder/gradle-one-jar/issues/34
pharsicle

Ecco una soluzione one-liner per creare un vaso modificando l'attività del vaso. Ho trovato questo per essere il più conveniente. Si noti che è necessario aggiungere configurations.runtimeper raggruppare le dipendenze di runtime nel singolo jar.
Quazi Irfan,

Ho trovato "plug-in dell'applicazione" adatto e flessibile per le mie esigenze. Permette anche di comprimere tutto in zip e includere / escludere file extra in quella zip. Inoltre, è possibile aggiungere un altro script di avvio con un punto di ingresso aggiuntivo utilizzando un'attività personalizzata.
Kinornirvana,

Come eseguirò i file .tar/ .zipgenerati?
Tobiq,

35

Come altri hanno notato, affinché un file jar sia eseguibile, il punto di ingresso dell'applicazione deve essere impostato Main-Classnell'attributo del file manifest. Se i file della classe di dipendenza non sono collocati, devono essere impostati nella Class-Pathvoce del file manifest.

Ho provato tutti i tipi di combinazioni di plug-in e cosa non per il semplice compito di creare un vaso eseguibile e in qualche modo, includere le dipendenze. Tutti i plugin sembrano mancare in un modo o nell'altro, ma alla fine ho capito come volevo. Nessuno script misterioso, non un milione di mini file diversi che inquinano la directory di build, un file di script build abbastanza pulito e, soprattutto: non un milione di file di terze parti stranieri si sono fusi nel mio archivio jar.

Di seguito è riportato un copia-incolla da qui per comodità.

[Come fare] creare un file zip di distribuzione con barattoli di dipendenza nella sottodirectory /libe aggiungere tutte le dipendenze alla Class-Pathvoce nel file manifest:

apply plugin: 'java'
apply plugin: 'java-library-distribution'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.commons:commons-lang3:3.3.2'
}

// Task "distZip" added by plugin "java-library-distribution":
distZip.shouldRunAfter(build)

jar {
    // Keep jar clean:
    exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'

    manifest {
        attributes 'Main-Class': 'com.somepackage.MainClass',
                   'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
    }
    // How-to add class path:
    //     /programming/22659463/add-classpath-in-manifest-using-gradle
    //     https://gist.github.com/simon04/6865179
}

Ospitato come sostanza qui .

Il risultato può essere trovato build/distributionse il contenuto decompresso appare così:

lib / commons-lang3-3.3.2.jar
MyJarFile.jar

Contenuto di MyJarFile.jar#META-INF/MANIFEST.mf:

Versione manifest: 1.0
Classe principale: com.somepackage.MainClass
Percorso di classe: lib / commons-lang3-3.3.2.jar


L'attuale jar dell'applicazione sarà anche nella directory 'lib' della distribuzione. Devi spostarlo in base alla directory principale o modificare questa riga: 'Class-Path': configurations.runtime.files.collect {"lib / $ it.name"} .join ('')} in questo: 'Class-Path': configurations.runtime.files.collect {"$ it.name"} .join ('')}
Marc Nuri,

1
@MarcNuri Sei sicuro? Ho provato a utilizzare questo approccio per la mia applicazione, e il vaso dell'applicazione corrente non si trovava nella libdirectory del file zip / tar prodotto, ma piuttosto nella libdirectory padre, come suggerisce questa risposta. Questa soluzione sembrava funzionare perfettamente per me.
thejonwithnoh,

1
@thejonwithnoh Mi dispiace, hai ragione. Non ho visto la soluzione proposta per utilizzare il plug-in "java-library-distribution". Nel mio caso sto semplicemente usando il plugin "application" che fa lo stesso lavoro con la differenza principale che tutti i file jar ( incluso il jar dell'applicazione) si trovano nella directory "lib". In tal modo, il passaggio "lib/$it.name"a "$it.name"farà il lavoro.
Marc Nuri,

28

La soluzione più semplice per me è stata quella di utilizzare il plug-in gradle-shadow

Oltre ad applicare il plugin tutto ciò che deve essere fatto è:

Configura l'attività jar per mettere manifest la tua classe Main

jar {
  manifest {
   attributes 'Main-Class': 'com.my.app.Main'
  }
}

Esegui l'attività gradle

./gradlew shadowJar

Prendi l' app-versione-all.jar da build / libs /

E infine eseguilo tramite:

java -jar app-version-all.jar


Quando eseguo questa build ottengo BUILD SUCCESSFUL ma quando provo a eseguire il file jar con java -jar build / libs / core-all-1.0.jar ottengo il seguente errore: Errore: Impossibile trovare o caricare la classe principale scanners.exchange. Principale causato da: java.lang.ClassNotFoundException: scanners.exchange.Main Sai come posso risolvere questo?
Luka Lopusina,

@LukaLopusina La classe che hai specificato non è nel tuo file JAR. Se stai usando kotlin, devi dirlo 'com.my.app.MainKt'. Senza ulteriori informazioni, non posso aiutarti ulteriormente.
byxor,

Il plug-in corrente Shadow v5. + È compatibile solo con Gradle 5.0+ e Java 7+.
Zon,

5

Hai provato l'attività 'installApp'? Non crea una directory completa con un set di script di avvio?

http://www.gradle.org/docs/current/userguide/application_plugin.html


Da quello che ho capito, installAppnon crea un META-INF/MANIFEST.MFfile. Sto facendo qualcosa di sbagliato?
Adotta il

1
Non vedo installAppl'attività nell'elenco delle attività del plug-in dell'applicazione . Intendi installDistinvece?
Quazi Irfan,

2
Sì, è installAppstato rinominato installDistin Gradle 3.0. Ecco la nota di rilascio .
Quazi Irfan,

4

Grazie Konstantin, ha funzionato come un fascino con poche sfumature. Per qualche ragione, specificare la classe principale come parte di jar manifest non ha funzionato e ha voluto invece l'attributo mainClassName. Ecco uno snippet di build.gradle che include tutto per farlo funzionare:

plugins {
  id 'java' 
  id 'com.github.johnrengelman.shadow' version '1.2.2'
}
...
...
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
...
...
mainClassName = 'com.acme.myapp.MyClassMain'
...
...
...
shadowJar {
    baseName = 'myapp'
}

Dopo aver eseguito gradle shadowJar, ottieni myapp- {version} -all.jar nella tua cartella di build che può essere eseguita come java -jar myapp- {version} -all.jar.


3

È possibile definire un artefatto jar nelle impostazioni del modulo (o nella struttura del progetto).

  • Fare clic con il tasto destro del mouse sul modulo> Apri impostazioni modulo> Artefatti> +> JAR> dai moduli con dipendenze.
  • Imposta la classe principale.

Creare un barattolo è quindi facile come fare clic su "Crea artefatto ..." dal menu Crea. Come bonus, puoi impacchettare tutte le dipendenze in un singolo vaso.

Testato su IntelliJ IDEA 14 Ultimate.


2

Ho controllato alcuni collegamenti per la soluzione, infine ho fatto i passaggi di seguito indicati per farlo funzionare. Sto usando Gradle 2.9.

Apporta le seguenti modifiche al tuo file build, gradle:

  1. Menzione plugin:

    apply plugin: 'eu.appsatori.fatjar'
  2. Fornisci il Buildscript:

    buildscript {
    repositories {
        jcenter()
    }
    
    dependencies {
        classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
    }
    }
  3. Fornire la classe principale:

    fatJar {
      classifier 'fat'
      manifest {
        attributes 'Main-Class': 'my.project.core.MyMainClass'
      }
      exclude 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.SF'
    }
  4. Crea il fatjar:

    ./gradlew clean fatjar
  5. Esegui il fatjar da / build / libs /:

    java -jar MyFatJar.jar

1
Dal 2019: questo suggerimento non funziona qui. Nessuna dipendenza è inclusa nel fatjar
carl del

1

Puoi usare il plugin SpringBoot:

plugins {
  id "org.springframework.boot" version "2.2.2.RELEASE"
}

Crea il barattolo

gradle assemble

E poi eseguirlo

java -jar build/libs/*.jar

Nota: il tuo progetto NON deve essere un progetto SpringBoot per utilizzare questo plugin.

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.