Створення JAR, що працює, з Gradle


148

До цього часу я створював файли JAR, які можна запустити, за допомогою функції Eclipse "Export ...", але тепер я перейшов на IntelliJ IDEA та Gradle для автоматизації побудови.

Деякі статті тут пропонують плагін "application", але це не зовсім призводить до очікуваного результату (просто JAR, відсутні сценарії запуску чи щось подібне).

Як я можу досягти того самого результату, який Eclipse робить із діалоговим вікном "Експорт ..."?

Відповіді:


164

Виконаний файл jar - це лише jar-файл, що містить в своєму маніфесті запис Main-Class. Тому вам просто потрібно налаштувати завдання jar , щоб додати цей запис у свій маніфест:

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

Можливо, вам також знадобиться додати записи маніфесту до маніфесту, але це буде зроблено так само.

Див. Http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html


6
Це, здається, те, що я шукав; але: я оголосив вже залежності в build.gradle, чи дійсно мені потрібно вручну додавати шлях до класу чи можу я повторно використовувати декларацію залежності?
Ганнес

Ви повинні мати змогу переглядати бібліотеки всередині конфігурації 'runtime' та об'єднувати їх для створення значення атрибута Class-Path.
JB Nizet

3
Що ви маєте на увазі під "insid" конфігурацією "часу виконання"? Вибачте за дурні питання, я зовсім новачок у Gradle ...
Ханнес,

Плагін gradle java визначає 4 "конфігурації", що відповідають 4 різним класовим шляхом: compile (використовується для компіляції файлів Java), testCompile (який використовується для компіляції тестових вихідних файлів Java), час виконання (який використовується для виконання програми) та testRuntime (який використовується для виконання тестів). Дивіться gradle.org/docs/current/userguide/…
JB Nizet

Ах, спасибі - ніж я зрозумів це правильно та встигаю створити JAR, тепер я заплутався із створенням classpath ;-) Дякую за вашу допомогу!
Ганнес

98

Відповіді JB Nizet та Jorge_B правильні.

У своїй найпростішій формі створення виконавчого JAR за допомогою Gradle - це лише питання додавання відповідних записів до маніфесту . Однак набагато частіше зустрічатися залежностей, які потрібно включити на класний шлях, що робить цей підхід складним на практиці.

Плагін додаток забезпечує альтернативний підхід; замість створення виконуваного JAR, він передбачає:

  • runзадача легко полегшити запуск програми безпосередньо з збірки
  • installDistзадача , яка формує структуру каталогів , включаючи вбудований JAR, все баночки , що це залежить від, і скрипт для запуску , який тягне все це разом в програму ви можете запустити
  • distZipі distTarзавдання, які створюють архіви, що містять повний розподіл додатків (сценарії запуску та JAR)

Третій підхід полягає у створенні так званого "жирового JAR", який є виконавчим JAR, що включає не тільки код вашого компонента, але і всі його залежності. Є кілька різних плагінів, які використовують такий підхід. Я включив посилання на декілька, про які мені відомо; Я впевнений, що є більше.


Щойно спробував тінь і однобанку. Я дотримуватимусь однієї банки: вона простіша та легша у використанні. Класно! дякую
Яко

На жаль, один jar не працює з останніми версіями Gradle. Дивіться, наприклад, github.com/rholder/gradle-one-jar/isissue/34
pharsicle

Ось однолінійне рішення для створення однієї банки, змінивши завдання банку. Я вважаю це найзручнішим. Зауважте, що вам потрібно додати configurations.runtimeдо залежності залежності від часу виконання в одній банці.
Куазі Ірфан

Я виявив, що "плагін програми" є відповідним і досить гнучким для моєї потреби. Це дозволяє також спакувати все, щоб поштовувати, та включати / виключати зайві файли у цьому ZIP. Крім того, можна додати ще один сценарій запуску з додатковою точкою входу за допомогою спеціального завдання.
kinORnirvana

Як мені виконати створені .tar/ .zipфайли?
Тобік

35

Як зазначали інші, для того, щоб файл jar можна було виконати, вхідна програма програми повинна бути встановлена ​​в Main-Classатрибуті файлу маніфесту. Якщо файли класу залежності не розміщуються, їх потрібно встановити у Class-Pathзаписі файлу маніфесту.

Я спробував усілякі комбінації плагінів, і що не для простого завдання - створити виконуваний jar і якось так чи інакше, включати залежності. У всіх плагінах, здається, бракує так чи інакше, але нарешті я отримав це так, як хотів. Ніякі загадкові сценарії, ні мільйон різних міні-файлів, що забруднюють каталог збірок, досить чистий файл сценарію збірки, і перш за все: не мільйон іноземних файлів сторонніх класів не об’єдналися в мій архівний 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
}

Хостинг як суть тут .

Результат можна знайти в, build/distributionsі розпакований вміст виглядає так:

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

Зміст MyJarFile.jar#META-INF/MANIFEST.mf:

Версія маніфесту: 1.0
Основний клас: com.somepackage.MainClass
Class-Path: lib / commons-lang3-3.3.2.jar


Поточна банку додатків також буде знаходитись у каталозі "lib" дистрибутива. Ви повинні або перемістити його у верхній каталог, або змінити цей рядок: 'Class-Path': configurations.runtime.files.collect {"lib / $ it.name"} .join ('')} до цього: 'Class-Path': configurations.runtime.files.collect {"$ it.name"} .join ('')}
Марк Нурі

1
@MarcNuri Ви впевнені? Я спробував використати цей підхід для свого застосування, і поточна банку додатків знаходилася не в libкаталозі створеного файлу zip / tar, а, скоріше, знаходилась у libбатьківській директорії, як це підказує. Це рішення, здавалося, прекрасно працює для мене.
thejonwithnoh

1
@thejonwithnoh Вибачте, ви праві. Я не бачив запропонованого рішення використовувати плагін "java-library-distribution". У моєму випадку я просто використовую плагін "application", який виконує ту саму роботу, головна відмінність у тому, що всі файли jar ( включаючи jar jar) знаходяться в каталозі "lib". Таким чином, зміна "lib/$it.name"на "$it.name"виконає свою роботу.
Марк Нурі

28

Найменшим рішенням для мене було використання плагіну gradle-shadow

Крім застосування плагіна, все, що потрібно зробити, це:

Налаштуйте завдання jar, щоб розмістити ваш основний клас у маніфесті

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

Виконайте завдання градуї

./gradlew shadowJar

Візьміть app-version-all.jar з build / libs /

І нарешті виконати це за допомогою:

java -jar app-version-all.jar


Коли я роблю цю збірку, я отримую BUILD SUCCESSFUL, але коли я намагаюся запустити jar файл з java -jar build / libs / core-all-1.0.jar, я отримую таку помилку: Помилка: Не вдалося знайти або завантажити сканер основного класу.exchange. Основна причина: java.lang.ClassNotFoundException: scanners.exchange.Main Чи знаєте ви, як я можу це вирішити?
Лука Лопусіна

@LukaLopusina Клас, який ви вказали, відсутній у вашому файлі JAR. Якщо ви використовуєте kotlin, вам потрібно сказати 'com.my.app.MainKt'. Без додаткової інформації я не можу вам допомогти далі.
byxor

Поточний плагін Shadow v5. + Сумісний лише з Gradle 5.0+ та Java 7+.
Зона

5

Ви пробували завдання "installApp"? Чи не створюється повноцінний каталог із набором сценаріїв запуску?

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


Як я розумію, файл installAppне створює META-INF/MANIFEST.MF. Чи я щось роблю не так?
просування

1
Я не бачу installAppзавдання в списку завдань Плагіна додатка . Ти installDistзамість цього мав на увазі ?
Куазі Ірфан

2
Так, installAppбуло перейменовано installDistв Gradle 3.0. Ось примітка до випуску .
Куазі Ірфан

4

Дякую Костянтину, це спрацювало як шарм із кількома нюансами. Чомусь вказати основний клас як частину маніфесту 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.

Внесіть наступні зміни у файл складання, gradle:

  1. Згаданий плагін:

    apply plugin: 'eu.appsatori.fatjar'
  2. Надайте сценарій збірки:

    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. Створіть жир:

    ./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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.