Gradle ile çalıştırılabilir JAR oluşturma


154

Şimdiye kadar Eclipse "Export ..." işlevselliği aracılığıyla çalıştırılabilir JAR dosyaları oluşturdum, ancak şimdi yapı otomasyonu için IntelliJ IDEA ve Gradle'a geçtim.

Buradaki bazı makaleler "uygulama" eklentisini önermektedir, ancak bu tam olarak beklediğim sonuca götürmez (sadece bir JAR, başlangıç ​​komut dosyası veya buna benzer bir şey).

Eclipse'in "Dışa Aktar ..." iletişim kutusuyla yaptığı aynı sonucu nasıl elde edebilirim?

Yanıtlar:


166

Çalıştırılabilir bir jar dosyası, manifestinde bir Ana Sınıf girişi içeren bir jar dosyasıdır. Bu nedenle, bu girişi bildirimine eklemek için jar görevini yapılandırmanız yeterlidir :

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

Ayrıca manifest'e sınıf yolu girişleri eklemeniz gerekebilir, ancak bu aynı şekilde yapılır.

Bkz. Http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html


6
Bu aradığım gibi görünüyor; ancak: build.gradle'da zaten bağımlılıkları bildirdim, sınıf yolunu gerçekten manuel olarak eklemem gerekir mi yoksa bağımlılık bildirimimi yeniden kullanabilir miyim?
Hannes

'Çalışma zamanı' yapılandırması içindeki kitaplıklar arasında döngü yapabilmeli ve Sınıf-Yol öznitelik değerini oluşturmak için bunları birleştirebilmelisiniz.
JB Nizet

4
"Çalışma zamanı" yapılandırmasını inseid ile ne demek istiyorsun? Aptalca sorular için özür dilerim, Gradle'da oldukça yeniyim ...
Hannes

Gradle java eklentisi 4 farklı sınıf yoluna karşılık gelen 4 "konfigürasyonu" tanımlar: derleme (Java dosyalarını derlemek için kullanılır), testCompile (test Java kaynak dosyalarını derlemek için kullanılır), çalışma zamanı (uygulamayı çalıştırmak için kullanılır) ve testRuntime (testleri yürütmek için kullanılır). Bkz gradle.org/docs/current/userguide/...
JB NIZET

Ah, teşekkürler - doğru anladığımdan ve JAR'ı inşa etmeyi başardığımdan, şimdi sınıf yolunu oluşturmakla uğraşıyorum ;-) Yardımın için çok teşekkürler!
Hannes

100

Hem JB Nizet hem de Jorge_B'nin cevapları doğru.

En basit haliyle, Gradle ile yürütülebilir bir JAR oluşturmak, bildirime uygun girdileri eklemek meselesidir . Ancak, sınıf yoluna dahil edilmesi gereken bağımlılıklara sahip olmak çok daha yaygındır ve bu da bu yaklaşımı pratikte zorlaştırır.

Uygulama eklenti alternatif bir yaklaşım sağlar; yürütülebilir bir JAR oluşturmak yerine şunları sağlar:

  • runuygulamanın doğrudan derlemeden kolayca çalıştırılmasını kolaylaştırmak için bir görev
  • installDistyerleşik JAR, bağlı olduğu tüm JAR'lar ve hepsini birlikte çalıştırabileceğiniz bir programa çeken bir başlangıç ​​betiği dahil olmak üzere bir dizin yapısı oluşturan bir görev
  • distZipve distTareksiksiz bir uygulama dağıtımı içeren arşivler oluşturan görevler (başlangıç ​​komut dosyaları ve JAR'lar)

Üçüncü bir yaklaşım, yalnızca bileşeninizin kodunu değil, aynı zamanda tüm bağımlılıklarını da içeren yürütülebilir bir JAR olan "şişman JAR" olarak adlandırılan bir JAR oluşturmaktır. Bu yaklaşımı kullanan birkaç farklı eklenti var. Bildiğim birkaçına bağlantılar ekledim; Eminim daha fazlası vardır.


Sadece gölge ve tek kavanoz denedim. Tek kavanozda kalacağım: daha basit ve kullanımı daha kolay. Güzel! teşekkürler
Jako

Maalesef tek kavanoz Gradle'ın son sürümleriyle çalışmıyor. Örneğin bkz. Github.com/rholder/gradle-one-jar/issues/34
pharsicle

İşte kavanoz görevini değiştirerek tek kavanoz oluşturmak için tek astarlı bir çözüm. Bunu en uygun olanı buldum. configurations.runtimeTek kavanozda çalışma zamanı bağımlılıklarını paketlemek için eklemeniz gerektiğini unutmayın .
Quazi Irfan

"Uygulama eklentisi" nin ihtiyacıma uygun ve yeterince esnek olduğunu buldum. Ayrıca, her şeyi sıkıştırmak ve bu zip dosyasındaki fazladan dosyaları dahil etmek / hariç tutmak için paketlemeye izin verir. Ayrıca, özel görevi kullanarak ek giriş noktası olan başka bir başlatıcı komut dosyası eklemek mümkündür.
kinORnirvana

Oluşturulan .tar/ .zipdosyalarını nasıl çalıştırırım ?
Tobiq

35

Başkalarının da belirttiği gibi, bir jar dosyasının çalıştırılabilir olması için, uygulamanın giriş noktasının Main-Classbildirim dosyasının özniteliğinde ayarlanması gerekir . Bağımlılık sınıfı dosyaları birlikte konumlandırılmamışsa Class-Path, bunların bildirim dosyasının girişinde ayarlanması gerekir .

Her türlü eklenti kombinasyonunu denedim ve çalıştırılabilir bir jar oluşturmak gibi basit bir görev için değil, bir şekilde bağımlılıkları da içeriyor. Tüm eklentiler bir şekilde eksik görünüyor, ancak sonunda istediğim gibi edindim. Hiçbir gizemli betik yok, derleme dizinini kirleten bir milyon farklı mini dosya, oldukça temiz bir yapı betik dosyası ve hepsinden önemlisi: jar arşivimde bir milyon yabancı üçüncü taraf sınıf dosyası birleştirilmedi.

Aşağıda, size kolaylık sağlamak için buradan kopyalayıp yapıştırılmıştır .

[Nasıl yapılır] alt dizinde bağımlılık kavanozları içeren bir dağıtım zip dosyası oluşturun /libve tüm bağımlılıkları Class-Pathmanifest dosyasındaki girişe ekleyin :

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
}

Burada bir özet olarak barındırılıyor .

Sonuç build/distributionsşurada bulunabilir ve sıkıştırılmış içerikler şu şekilde görünür:

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

İçeriği MyJarFile.jar#META-INF/MANIFEST.mf:

Manifest-Sürümü: 1.0
Ana-Sınıf: com.somepackage.MainClass
Sınıf-Yol: lib / commons-lang3-3.3.2.jar


Mevcut uygulama kavanozu da dağıtımın 'lib' dizininde olacaktır. Ya onu en üst dizine taşımak ya da şu satırı değiştirmek zorundasınız: 'Class-Path': configuration.runtime.files.collect {"lib / $ it.name"} .join ('')}: 'Sınıf-Yolu': configuration.runtime.files.collect {"$ it.name"} .join ('')}
Marc Nuri

1
@MarcNuri Emin misin? Benim uygulama için bu yaklaşım kullanmayı denediler ve mevcut uygulama kavanoz oldu değil de libüretilen zip / tar dosyasının dizine ziyade oldu libbu cevap da anlaşılacağı gibi, 'ın üst dizinde. Bu çözüm benim için mükemmel çalışıyordu.
thejonwithnoh

1
@thejonwithnoh Üzgünüm, haklısın. "Java-kitaplık dağıtımı" eklentisini kullanmak için önerilen çözümü görmedim. Benim durumumda, tüm jar dosyalarının ( uygulama kavanozu dahil ) "lib" dizininde yer alması arasındaki temel farkla aynı işi yapan "uygulama" eklentisini kullanıyorum . Böylece değişen "lib/$it.name"için "$it.name"iş yapacak.
Marc Nuri

30

Benim için en az çaba gerektiren çözüm, gradle-shadow-eklentisini kullanmaktı

Eklentiyi uygulamanın yanı sıra yapılması gereken tek şey:

Jar görevini, Main sınıfınızı manifest haline getirmek için yapılandırın

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

Gradle görevini çalıştırın

./gradlew shadowJar

Al app-versiyon-all.jar gelen yapı / kütüphaneleri /

Ve nihayet şu şekilde yürütün:

java -jar app-version-all.jar


Bu derlemeyi yaptığımda BUILD SUCCESSFUL elde ediyorum ancak jar dosyasını java -jar build / libs / core-all-1.0.jar ile çalıştırmaya çalıştığımda şu hatayı alıyorum: Hata: Ana sınıf scanners.exchange bulunamadı veya yüklenemedi. Ana Neden: java.lang.ClassNotFoundException: scanners.exchange.Main Bunu nasıl çözebileceğimi biliyor musunuz?
Luka Lopusina

@LukaLopusina Belirttiğiniz sınıf JAR dosyanızda yok. Kotlin kullanıyorsanız söylemeniz gerekir 'com.my.app.MainKt'. Daha fazla bilgi olmadan sana daha fazla yardımcı olamam.
byxor

Mevcut eklenti Shadow v5. + Yalnızca Gradle 5.0+ ve Java 7+ ile uyumludur.
Zon

5

'İnstallApp' görevini denediniz mi? Bir dizi başlangıç ​​komut dosyası içeren tam bir dizin oluşturmaz mı?

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


Anladığım kadarıyla installAppbir META-INF/MANIFEST.MFdosya oluşturmuyor . Yanlış bir şey mi yapıyorum?
advait

1
Uygulama EklentisinininstallApp görev listesinde görev göremiyorum . Onun yerine mi demek istedin ? installDist
Quazi Irfan

2
Evet, Gradle 3.0'da installAppyeniden adlandırıldı installDist. İşte sürüm notu .
Quazi Irfan

4

Teşekkürler Konstantin, birkaç nüansla bir cazibe gibi çalıştı. Bazı nedenlerden dolayı, jar bildiriminin bir parçası olarak ana sınıfı belirtmek pek işe yaramadı ve bunun yerine mainClassName özniteliğini istedi. İşte build.gradle'dan, çalışmasını sağlamak için her şeyi içeren bir snippet:

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'
}

Gradle shadowJar'ı çalıştırdıktan sonra, java -jar myapp- {version} -all.jar olarak çalıştırılabilen derleme klasörünüzde uygulamam- {version} -all.jar dosyasını alırsınız.


3

Modül ayarlarında (veya proje yapısında) bir akü öğesi tanımlayabilirsiniz.

  • Bağımlılık içeren modüllerden modüle sağ tıklayın> Modül ayarlarını aç> Yapılar> +> JAR>.
  • Ana sınıfı ayarlayın.

Bu durumda bir jar yapmak, Build menüsünden "Build artifact ..." ı tıklamak kadar kolaydır. Bonus olarak, tüm bağımlılıkları tek bir kavanozda paketleyebilirsiniz.

IntelliJ IDEA 14 Ultimate üzerinde test edilmiştir.


2

Çözüm için epeyce bağlantıları kontrol ettim, sonunda çalışmasını sağlamak için aşağıda belirtilen adımları yaptım. Gradle 2.9 kullanıyorum.

Derleme, gradle dosyanızda aşağıdaki değişiklikleri yapın:

  1. Bahsedilen eklenti:

    apply plugin: 'eu.appsatori.fatjar'
    
  2. Buildscript'i sağlayın:

    buildscript {
    repositories {
        jcenter()
    }
    
    dependencies {
        classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
    }
    }
    
  3. Ana Sınıfı Sağlayın:

    fatJar {
      classifier 'fat'
      manifest {
        attributes 'Main-Class': 'my.project.core.MyMainClass'
      }
      exclude 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.SF'
    }
    
  4. Fatjar oluşturun:

    ./gradlew clean fatjar
    
  5. Fatjar'ı / build / libs / dizininden çalıştırın:

    java -jar MyFatJar.jar
    

1
2019'dan: Bu öneri burada çalışmıyor. Bağımlılık yok
carl

2

SpringBoot eklentisini kullanabilirsiniz:

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

Kavanozu oluşturun

gradle assemble

Ve sonra çalıştır

java -jar build/libs/*.jar

Not: Bu eklentiyi kullanmak için projenizin bir SpringBoot projesi olması GEREKMEZ.


0
  1. Manifest'inize Ana Sınıfı Yapılandırın

Gradle projesini kullanıyorsanız, aşağıdakileri build.gradle'a eklemeniz yeterlidir

jar {
    manifest {
        attributes(
               'Main-Class': 'pokerhandscorer.PokerHandScorer'
        )
    }
}
  • 'Pokerhandscorer' paket adının adıdır ve PokerHandScorer ana sınıf adıdır

Bu, \ build \ libs {jarFilename} .jar dosyanıza bir jar dosyası oluşturur.

  1. Jar dosyasını java -jar /{path}/{jarFileName.jar} kullanarak çalıştırın

java -jar /{path}/{jarFileName.jar}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.