การสร้าง JAR ที่รันได้ด้วย Gradle


148

จนถึงตอนนี้ฉันสร้างไฟล์ JAR ที่รันได้ผ่าน Eclipse "ส่งออก ... " ฟังก์ชั่นทั้งหมด แต่ตอนนี้ฉันเปลี่ยนเป็น IntelliJ IDEA และ Gradle เพื่อสร้างระบบอัตโนมัติ

บทความบางส่วนที่นี่แนะนำปลั๊กอิน "แอปพลิเคชัน" แต่สิ่งนี้ไม่ได้นำไปสู่ผลลัพธ์ที่ฉันคาดหวัง (แค่ JAR ไม่มีสคริปต์เริ่มต้นหรืออะไรแบบนี้)

ฉันจะบรรลุผลลัพธ์เดียวกันได้อย่างไร Eclipse จะทำอย่างไรกับกล่องโต้ตอบ "ส่งออก ... "

คำตอบ:


164

ไฟล์ jar ที่ปฏิบัติการได้เป็นเพียงไฟล์ jar ที่มีรายการ Main-Class ในไฟล์ Manifest ดังนั้นคุณเพียงแค่ต้องกำหนดค่างาน jarเพื่อเพิ่มรายการนี้ในรายการ:

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

คุณอาจต้องเพิ่มรายการพา ธ คลาสในรายการ แต่จะทำแบบเดียวกัน

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


6
นี่เป็นสิ่งที่ฉันกำลังมองหา แต่: ฉันประกาศการขึ้นต่อกันแล้วใน build.gradle ฉันต้องเพิ่มคลาสพา ธ ด้วยตนเองหรือฉันจะใช้การประกาศการพึ่งพาของฉันอีกครั้งได้หรือไม่
Hannes

คุณควรจะสามารถวนลูปผ่านไลบรารีภายในการกำหนดค่า 'รันไทม์' และเชื่อมต่อพวกมันเพื่อสร้างค่าแอตทริบิวต์คลาสพา ธ
JB Nizet

3
คุณหมายถึงอะไรกับ 'inseid the "runtime" configuration "? ขออภัยสำหรับคำถามโง่ผมค่อนข้างใหม่ในการ Gradle ...
ฮานเนส

ปลั๊กอิน java gradle กำหนด 4 "การกำหนดค่า" ที่สอดคล้องกับ 4 classpaths ที่แตกต่างกัน: คอมไพล์ (ใช้ในการรวบรวมไฟล์ Java), testCompile (ซึ่งใช้ในการรวบรวมไฟล์ต้นฉบับทดสอบ Java) รันไทม์ (ซึ่งใช้ในการรันแอปพลิเคชัน) และ testRuntime (ซึ่งใช้ในการดำเนินการทดสอบ) ดูgradle.org/docs/current/userguide/ …
JB Nizet

อ่าขอบคุณ - มากกว่าที่ฉันเข้าใจถูกต้องและจัดการเพื่อสร้าง JAR ตอนนี้ฉัน frickeling กับการสร้าง classpath ;-) ขอบคุณมากสำหรับความช่วยเหลือของคุณ!
Hannes

98

ทั้งคำตอบของ JB Nizet และ Jorge_B นั้นถูกต้อง

ในรูปแบบที่ง่ายที่สุดในการสร้าง JAR ปฏิบัติการด้วย Gradle เป็นเพียงเรื่องของการเพิ่มรายการที่เหมาะสมที่จะเป็นที่ประจักษ์ อย่างไรก็ตามมันเป็นเรื่องธรรมดามากที่จะมีการพึ่งพาที่จำเป็นต้องรวมอยู่ใน classpath ทำให้วิธีการนี้ยุ่งยากในการปฏิบัติ

ปลั๊กอินแอพลิเคชันมีแนวทางอื่น; แทนที่จะสร้าง JAR ที่สามารถเรียกทำงานได้จะให้:

  • runงานเพื่ออำนวยความสะดวกได้อย่างง่ายดายใช้โปรแกรมโดยตรงจากการสร้าง
  • installDistงานที่สร้างโครงสร้างไดเรกทอรีรวมทั้ง JAR สร้างทั้งหมดของขวดที่ว่ามันขึ้นอยู่กับและสคริปต์เริ่มต้นที่ดึงมันเข้าด้วยกันทั้งหมดลงในโปรแกรมที่คุณสามารถเรียกใช้
  • distZipและdistTarภารกิจที่สร้างไฟล์เก็บถาวรที่มีการกระจายแอ็พพลิเคชันที่สมบูรณ์ (สคริปต์เริ่มต้นและ JARs)

วิธีที่สามคือการสร้างสิ่งที่เรียกว่า "fat JAR" ซึ่งเป็น JAR แบบปฏิบัติการได้ซึ่งไม่เพียง แต่ประกอบด้วยรหัสของส่วนประกอบของคุณ แต่ยังรวมถึงการพึ่งพาทั้งหมดด้วย มีปลั๊กอินที่แตกต่างกันเล็กน้อยที่ใช้วิธีนี้ ฉันได้รวมลิงก์ไปยังลิงก์ที่ฉันทราบแล้ว ฉันแน่ใจว่ามีมากขึ้น


เพิ่งลองเงาและขวดเดียว ฉันจะติดหนึ่งขวด: มันง่ายกว่าและใช้งานง่ายกว่า เย็น! ขอบคุณ
Jako

น่าเสียดายที่หนึ่งขวดไม่ทำงานกับ Gradle รุ่นล่าสุด ดูตัวอย่างเช่นgithub.com/rholder/gradle-one-jar/issues/34
pharsicle

นี่คือโซลูชันแบบหนึ่งซับในการสร้างหนึ่ง jar โดยแก้ไขภารกิจ jar ฉันพบว่าสิ่งนี้สะดวกที่สุด โปรดทราบว่าคุณต้องเพิ่มconfigurations.runtimeการพึ่งพารันไทม์บันเดิลในโถเดียว
Quazi Irfan

ฉันพบว่า "ปลั๊กอินของแอปพลิเคชัน" เหมาะสมและยืดหยุ่นเพียงพอสำหรับความต้องการของฉัน มันยังอนุญาตให้แพ็คทุกอย่างเพื่อ zip และรวม / แยกไฟล์พิเศษใน zip นั้น นอกจากนี้ยังเป็นไปได้ที่จะเพิ่มสคริปต์ตัวเรียกใช้งานด้วยจุดเริ่มต้นเพิ่มเติมโดยใช้งานที่กำหนดเอง
kinORnirvana

ฉันจะทำอย่างไร .tar.zipไฟล์/ สร้างขึ้นได้อย่างไร?
Tobiq

35

ดังที่คนอื่น ๆ ได้จดบันทึกไว้เพื่อให้ไฟล์ jar สามารถเรียกใช้งานได้จุดเข้าใช้งานของแอปพลิเคชันจะต้องตั้งค่าในMain-Classแอตทริบิวต์ของไฟล์รายการ หากไฟล์คลาสการพึ่งพาไม่ได้จัดวางดังนั้นจำเป็นต้องตั้งค่าไว้ในClass-Pathรายการของไฟล์รายการ

ฉันได้ลองชุดค่าผสมทุกชนิดแล้วและสิ่งที่ไม่เกี่ยวกับงานง่าย ๆ ในการสร้าง jar ที่ใช้งานได้และอย่างใดอย่างหนึ่งรวมถึงการพึ่งพา ปลั๊กอินทั้งหมดดูเหมือนจะขาดไปไม่ทางใดก็ทางหนึ่ง แต่ในที่สุดฉันก็ได้มันมาเหมือนที่ฉันต้องการ ไม่มีสคริปต์ลึกลับไม่ใช่ไฟล์ขนาดเล็กหลายล้านไฟล์ที่สร้างมลภาวะต่อการสร้างไฟล์สคริปต์สร้างที่ค่อนข้างสะอาดและเหนือสิ่งอื่นใดไม่ใช่ไฟล์ระดับบุคคลที่สามจากต่างประเทศที่รวมอยู่ในที่เก็บถาวรของฉัน

ต่อไปนี้เป็นสำเนาการวางจากที่นี่เพื่อความสะดวกของคุณ ..

[วิธีการ] สร้างไฟล์ zip การกระจายพร้อมไหการพึ่งพาในไดเรกทอรีย่อย/libและเพิ่มการอ้างอิงทั้งหมดไปยังClass-Pathรายการในไฟล์รายการ:

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
}

Hosted เป็นส่วนสำคัญที่นี่

สามารถพบผลลัพธ์ได้build/distributionsและเนื้อหาที่คลายซิปจะมีลักษณะดังนี้:

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

เนื้อหาของMyJarFile.jar#META-INF/MANIFEST.mf:

Manifest-Version: 1.0
Main-Class: com.somepackage.MainClass
Class-Path: lib / commons-lang3-3.3.2.jar


แอ็พพลิเคชัน jar ปัจจุบันจะอยู่ในไดเร็กทอรี 'lib' ของการแจกจ่ายด้วย คุณต้องย้ายมันโดยไปยังไดเรกทอรีด้านบนหรือเปลี่ยนบรรทัดนี้: 'Class-Path': configurations.runtime.files.collect {"lib / $ it.name"} .join ('')} เป็น: 'Class-Path': configurations.runtime.files.collect {"$ it.name"} .join ('')}
Marc Nuri

1
@MarcNuri คุณแน่ใจหรือไม่ ฉันลองใช้วิธีการนี้กับแอปพลิเคชันของฉันและ jar ของแอปพลิเคชันปัจจุบันไม่ได้อยู่ในlibไดเรกทอรีของไฟล์ zip / tar ที่ผลิตขึ้น แต่อยู่ในlibไดเรกทอรีหลักของมัน วิธีนี้ดูเหมือนจะทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน
thejonwithnoh

1
@thejonwithnoh ฉันขอโทษคุณพูดถูก ฉันไม่เห็นวิธีแก้ปัญหาที่เสนอให้ใช้ปลั๊กอิน "java-library-distribution" ในกรณีของฉันฉันเพียงแค่ใช้ปลั๊กอิน "แอปพลิเคชัน" ซึ่งทำงานเดียวกันกับความแตกต่างหลักที่ไฟล์ jar ทั้งหมด ( รวมถึงแอปพลิเคชัน jar) ตั้งอยู่ในไดเรกทอรี "lib" ดังนั้นการเปลี่ยน"lib/$it.name"ไป"$it.name"จะทำงาน
Marc Nuri

28

โซลูชันความพยายามน้อยที่สุดสำหรับฉันคือการใช้gradle-shadow-plugin

นอกจากการใช้ปลั๊กอินสิ่งที่ต้องทำคือ:

กำหนดค่าภารกิจ jar เพื่อให้คลาส Main ของคุณเป็นรายการ

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

เรียกใช้งานการไล่ระดับสี

./gradlew shadowJar

ใช้แอปเวอร์ชัน version.jarจากbuild / libs /

และในที่สุดก็รันมันผ่าน:

java -jar app-version-all.jar

2
นี่เป็นเต็มรูปแบบbuild.gradleตัวอย่างเช่น
แบรด Turek

เมื่อฉันทำสิ่งนี้ฉันได้รับ BUILD SUCCESSFUL แต่เมื่อฉันพยายามเรียกใช้ไฟล์ jar ด้วย java -jar build / libs / core-all-1.0.jar ฉันได้รับข้อผิดพลาดดังต่อไปนี้: ข้อผิดพลาด: ไม่พบหรือโหลด scanners.exchange ระดับหลัก สาเหตุหลักจาก: java.lang.ClassNotFoundException: scanners.exchange.Main คุณรู้ไหมว่าฉันจะแก้ปัญหานี้ได้อย่างไร?
Luka Lopusina

@LukaLopusina คลาสที่คุณระบุไม่ได้อยู่ในไฟล์ JAR ของคุณ หากคุณกำลังใช้ Kotlin 'com.my.app.MainKt'คุณจะต้องบอกว่า หากไม่มีข้อมูลเพิ่มเติมฉันไม่สามารถช่วยคุณได้อีก
byxor

ปลั๊กอินปัจจุบัน Shadow v5. + เข้ากันได้กับ Gradle 5.0+ และ Java 7+ เท่านั้น
Zon

5

คุณลองใช้งาน 'installApp' แล้วหรือยัง มันไม่ได้สร้างไดเรกทอรีเต็มรูปแบบด้วยชุดของสคริปต์เริ่มต้นหรือไม่?

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


จากสิ่งที่ฉันเข้าใจinstallAppไม่ได้สร้างMETA-INF/MANIFEST.MFไฟล์ ฉันกำลังทำอะไรผิดหรือเปล่า?
advait

1
ฉันไม่เห็นinstallAppงานในรายการงานของแอพลิเคชันปลั๊กอิน คุณหมายถึงอะไรinstallDistแทน
Quazi Irfan

2
ใช่installAppเปลี่ยนชื่อเป็นinstallDistใน Gradle 3.0 นี่คือเอกสารเผยแพร่
Quazi Irfan

4

ขอบคุณ Konstantin มันใช้งานได้อย่างมีเสน่ห์มีความแตกต่างเล็กน้อย ด้วยเหตุผลบางอย่างการระบุคลาสหลักเป็นส่วนหนึ่งของรายการ jar ไม่ได้ผลและต้องการแอตทริบิวต์ mainClassName แทน นี่คือตัวอย่างจาก build.gradle ที่รวมทุกอย่างเพื่อให้ทำงาน:

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 คุณจะได้รับ myapp- {version} -all.jar ในโฟลเดอร์บิลด์ซึ่งสามารถรันเป็น java -jar myapp- {version} -all.jar


3

คุณสามารถกำหนดสิ่งประดิษฐ์ jar ในการตั้งค่าโมดูล (หรือโครงสร้างโครงการ)

  • คลิกขวาที่โมดูล> เปิดการตั้งค่าโมดูล> สิ่งประดิษฐ์> +> JAR> จากโมดูลที่ขึ้นต่อกัน
  • ตั้งคลาสหลัก

การสร้างไหนั้นทำได้ง่ายเพียงแค่คลิก "สร้างสิ่งประดิษฐ์ ... " จากเมนูสร้าง เป็นโบนัสคุณสามารถจัดเก็บการอ้างอิงทั้งหมดไว้ในโถเดียว

ทดสอบกับ IntelliJ IDEA 14 Ultimate


2

ฉันตรวจสอบการเชื่อมโยงบางอย่างเพื่อหาทางออกในที่สุดก็ทำตามขั้นตอนด้านล่างเพื่อให้มันใช้งานได้ ฉันใช้ Gradle 2.9

ทำการเปลี่ยนแปลงต่อไปนี้ในไฟล์ build, gradle ของคุณ:

  1. ปลั๊กอินที่กล่าวถึง:

    apply plugin: 'eu.appsatori.fatjar'
  2. ระบุ Buildscript:

    buildscript {
    repositories {
        jcenter()
    }
    
    dependencies {
        classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
    }
    }
  3. ระบุชั้นเรียนหลัก:

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

    ./gradlew clean fatjar
  5. รัน fatjar จาก / build / libs /:

    java -jar MyFatJar.jar

1
จากปี 2019: คำแนะนำนี้ใช้ไม่ได้ที่นี่ ไม่มีการอ้างอิงจะรวมอยู่ใน fatjar
คาร์ล

1

คุณสามารถใช้ปลั๊กอิน SpringBoot:

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

สร้างโถ

gradle assemble

จากนั้นเรียกใช้

java -jar build/libs/*.jar

หมายเหตุ: โครงการของคุณไม่จำเป็นต้องเป็นโครงการ SpringBoot เพื่อใช้ปลั๊กอินนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.