GitHub - sbtsbt-Assembly Розгортання жирних JAR-файлів

Розгортайте жирні JAR. Перезапустіть процеси.

розгортання

sbt-Assembly - це плагін sbt, спочатку перенесений з codahale's assembly-sbt, який, на мою думку, був натхненний плагіном збірки Maven. Мета проста: Створіть жирний JAR для вашого проекту з усіма його залежностями.

  • sbt
  • Пекуче бажання мати просту процедуру розгортання.

Повідомлення про проблеми та внесок

Перш ніж надіслати мені електронного листа, уважно прочитайте Правила звітності про проблеми. Двічі. (Не пишіть мені)

Використання опублікованого плагіна

Додайте sbt-Assembly як залежність у project/plugins.sbt:

(Можливо, вам доведеться перевірити теги цього проекту, щоб побачити останню версію.)

Оскільки sbt-Assembly тепер є автоматичним плагіном, який запускається для всіх проектів за допомогою JvmPlugin, він не повинен вимагати додаткових налаштувань для включення завдання складання у ваш проект. Детальніше про те, як здійснити оновлення зі старішої sbt-збірки, дивіться у посібнику з міграції.

Застосування плагіна до багатопроектного build.sbt

Наприклад, ось мультипроект build.sbt:

У наведеному вище прикладі як проект програми, так і проект utils не запускають тести під час складання. Проект програми встановлює основний клас, тоді як проект utils встановлює ім'я свого файлу jar.

Тепер у вас буде чудове нове завдання збірки, яке скомпілює ваш проект, запустить тести, а потім упакує файли класів та всі ваші залежності в один файл JAR: target/scala_X.X.X/projectname-Assembly-X.X.X.jar .

Якщо ви вказали mainClass у збірці в build.sbt (або просто дозволите йому самовизначення), то у вас вийде повністю виконуваний JAR, готовий до розгортання.

Ось список ключів, які можна перенаправити для завдання збірки.

Наприклад, ім'я банки можна встановити наступним чином у build.sbt:

Щоб пропустити тест під час складання,

Щоб встановити явний основний клас,

Виключення явного основного класу з вашої збірки вимагає чогось трохи іншого

Якщо декілька файлів мають один і той самий відносний шлях (наприклад, ресурс з іменем application.conf у декількох залежностях JAR), стратегія за замовчуванням полягає в тому, щоб перевірити, чи всі кандидати мають однаковий вміст, і в іншому випадку помилка. Цю поведінку можна налаштувати на основі кожного шляху, використовуючи одну з наступних вбудованих стратегій або написавши власну:

  • MergeStrategy.deduplicate є типовим описаним вище
  • MergeStrategy.first вибирає перший із відповідних файлів у порядку шляху до класу
  • MergeStrategy.last вибирає останню
  • MergeStrategy.singleOrError рятується повідомленням про помилку про конфлікт
  • MergeStrategy.concat просто об’єднує всі відповідні файли та включає результат
  • MergeStrategy.filterDistinctLines також об'єднується, але залишає дублікати в процесі
  • MergeStrategy.rename перейменовує файли, що походять з файлів jar
  • MergeStrategy.discard просто відкидає відповідні файли

Зіставлення імен шляхів для стратегій злиття здійснюється за допомогою параметра AssemblyMergeStrategy, який можна доповнити наступним чином:

ПРИМІТКА:

  • AssemblyMergeStrategy в збірці очікує функції. Ви не можете виконати AssemblyMergeStrategy у збірці: = MergeStrategy.first !
  • Деякі файли потрібно викинути або перейменувати в іншому випадку, щоб уникнути злому zip (через дублікат імені файлу) або юридичної ліцензії. Делегуйте обробку за замовчуванням до (AssemblyMergeStrategy у збірці) як наведений вище приклад відповідності шаблону.

До речі, перший шаблон у вищезазначеному випадку, використовуючи PathList (.) - це те, як ви можете вибрати javax/servlet/* з першої jar. Якщо за замовчуванням MergeStrategy.deduplicate не працює для вас, це, ймовірно, означає, що у вас є кілька версій якоїсь бібліотеки, витягнутої вашим графіком залежностей. Реальним рішенням є виправлення цього графіка залежності. Ви можете обійти це за допомогою MergeStrategy.first, але не дивуйтеся, коли побачите ClassNotFoundException .

Ось за замовчуванням:

Спеціальні MergeStrategy s можуть з’ясувати, звідки береться певний файл, використовуючи метод sourceOfFileForMerge на sbtassembly.AssemblyUtils, який приймає в якості параметрів тимчасовий каталог та один із файлів, переданих у стратегію.

Сторонні плагіни для злиття стратегій

Підтримку спеціальних стратегій злиття, що виходять за рамки загальної сфери застосування, можуть надати супутні плагіни, нижче наведено неповний список:

sbt-Assembly може відтіняти класи з ваших проектів або з бібліотечних залежностей. За підтримки Jar Jar Links перетворення байт-коду (через ASM) використовується для зміни посилань на перейменовані класи.

Ось правила тіні:

  • ShadeRule.rename ("x. **" -> "y. @ 1",.) .InAll Це головне правило.
  • ShadeRule.zap ("a.b.c"). InAll
  • ShadeRule.keep ("x. **"). InAll

Основне правило ShadeRule.rename використовується для перейменування класів. Усі посилання на перейменовані класи також будуть оновлені. Якщо назва класу відповідає кільком правилам, застосовуватиметься лише перше. Правила перейменування приймають варіант пар рядків

- це назва класу з необов’язковими символами підстановки. ** збігатиметься з будь-яким дійсним підрядком імені класу. Для узгодження одного компонента пакета (виключенням. Із відповідності) замість нього може бути використаний один *. це ім'я класу, яке за бажанням може посилатися на підрядки, відповідні підстановчим символам. Нумерована посилання доступна для кожного * або ** в

, починаючи зліва направо: @ 1, @ 2 тощо. Спеціальне посилання @ 0 містить ціле відповідне ім'я класу.

Замість .inAll зателефонуйте .inProject, щоб відповідати вашому джерелу проекту, або зателефонуйте .inLibrary ("commons-io"% "commons-io"% "2.4",.), Щоб відповідати певним залежностям бібліотеки. inProject та inLibrary (.) можуть бути пов’язані ланцюгами.

Правило ShadeRule.zap призводить до видалення будь-якого зіставленого класу з отриманого файлу jar. Усі правила zap обробляються перед перейменуванням правил.

Правило ShadeRule.keep позначає всі зіставлені класи як "коріння". Якщо визначено якісь правила збереження, усі класи, до яких неможливо дістатися з коренів за допомогою аналізу залежностей, відкидаються під час написання вихідного jar. Це останній крок у процесі, після перейменування та створення.

Щоб побачити детальний вивід для затінення:

Класи Scala містять анотацію, яка, крім усього іншого, містить усі символи, на які посилається цей клас. Починаючи з sbt-зборів XXX, правила перейменування застосовуватимуться і до цих анотацій, що дозволяє компілювати або відображати затінену бібліотеку.

Наразі це обмежується перейменуванням пакетів. Перейменування назв класів не буде працювати і спричинить помилки компілятора під час компіляції проти затіненої бібліотеки.

Виключаючи JAR-файли та файли

Якщо вам потрібно сказати sbt-Assembly ігнорувати JAR-файли, ви, мабуть, робите це неправильно. завдання збірки захоплює JAR-файли Deps із шляху до класу вашого проекту. Спробуйте спочатку виправити шлях до класу.

Якщо ви намагаєтеся виключити файли JAR, які вже є частиною контейнера (наприклад, Spark), розгляньте можливість застосування залежної бібліотеки до "наданої" конфігурації:

Maven визначає "наданий" як:

Це схоже на компіляцію, але означає, що ви очікуєте, що JDK або контейнер забезпечують залежність під час виконання. Наприклад, під час створення веб-програми для Java Enterprise Edition, ви повинні встановити залежність від API сервлетів та пов'язаних API Java EE до передбаченого обсягу, оскільки веб-контейнер забезпечує ці класи. Цей обсяг доступний лише на шляху до класу компіляції та тестування і не є транзитивним.

Залежність буде частиною компіляції та тесту, але виключена із середовища виконання. Якщо ви, люди Spark, хочете включити "забезпечені" залежності назад для запуску, @douglaz запропонував однолінійне рішення на StackOverflow sbt: як я можу додати "надані" залежності назад до шляху запуску/тестування завдань ?:

Виключити конкретні транзитивні депи

Можливо, ви думаєте про виключення файлів JAR через конфлікти злиття. Конфлікт злиття файлів * .class вказує на патологічний шлях до класу, часто через немодульний пакет JAR-файлів або SLF4J, а не на проблему зі збіркою. Ось що відбувається, коли ви намагаєтеся створити жирний JAR із включеною Spark:

У наведеному вище випадку два окремі файли JAR javax.servlet-2.5.0.v201103041518.jar та servlet-api-2.5-20081211.jar визначають javax/servlet/SingleThreadModel.class! Подібним чином також конфлікти щодо common-beanutils та EsotericSoftware/minlog. Ось як виселити конкретні транзитивні відділи:

Іноді для того, щоб з’ясувати, які перехідні відділи виключити, потрібна трохи детективної роботи. Грай! поставляється з завданням dist, тому збірка не потрібна, але припустимо, ми хотіли запустити збірку. Це приносить покажчик-commonshttp4, що призводить до спільного реєстрації. Це конфліктує з jcl-over-slf4j, який повторно реалізує API ведення журналу. Оскільки депи додаються за допомогою build.sbt та playScalaSettings, ось один із способів обійти це:

Виключаючи конкретні файли

Щоб виключити певні файли, налаштуйте стратегію злиття:

Розбиття JAR-файлів вашого проекту та деп

Щоб створити файл JAR, що містить лише зовнішні залежності, введіть

Він призначений для використання з JAR, який містить лише ваш проект

ПРИМІТКА. Якщо ви використовуєте параметр -jar для java, він буде ігнорувати -cp, тому, якщо у вас є кілька файлів JAR, вам доведеться використовувати -cp і передати основний клас: java -cp "jar1.jar: jar2.jar" Main

Виключаючи JAR бібліотеки Scala

Виключити бібліотеку Scala (JAR, які починаються з scala- та входять до двійкового розподілу Scala), щоб запускатись за допомогою команди scala,

Якщо всі зусилля не вдаються, ось спосіб виключити файли JAR:

Ви також можете додати відбиток пальця SHA-1 до імені файлу збірки, це може допомогти вам визначити, чи він змінився, і, наприклад, чи потрібно розгорнути залежності,

За замовчуванням з міркувань продуктивності результат розпакування будь-яких файлів JAR залежностей на диск кешується від запуску до запуску. Цю функцію можна вимкнути, встановивши:

Крім того, жирний JAR кешується, тому його мітка часу змінюється лише при зміні вводу. Ця функція вимагає перевірки хешу SHA-1 усіх файлів * .class та хешу всіх файлів залежності * .jar. Якщо існує велика кількість файлів класів, це може зайняти багато часу, хоча з хешуванням jar-файлів, а не їх вмісту, швидкість нещодавно покращилася. Цю функцію можна вимкнути, встановивши:

Попередній сценарій запуску

Ви можете додати сценарій запуску до жирної банки. Цей скрипт буде дійсним сценарієм оболонки та пакету та зробить jar виконуваним у Unix та Windows. Якщо ви ввімкнете shebang, файл буде виявлено як виконуваний файл під Linux, але це призведе до появи повідомлення про помилку в Windows. У Windows просто додайте ".bat" до імені файлів, щоб зробити його виконуваним.

Це додасть наступний сценарій оболонки до банки.

Ви також можете додати до сценарію жиру лише сценарій оболонки наступним чином:

Публікація (не рекомендується)

Публікувати в світі жирні JAR не рекомендується, оскільки немодульні JAR викликають багато смутку. Можна подумати, що немодульність - це зручність, але вона швидко перетворюється на головний біль, коли користувачі виходять за межі прикладу коду Hello World. Якщо ви все-таки хочете опублікувати зібраний артефакт разом із завданням публікації та всіма іншими артефактами, додайте класифікатор збірки (або інший):

З: Незважаючи на стурбованих друзів, я все ще хочу публікувати товсті JAR-файли. Яку пораду ти маєш?

Ймовірно, вам доведеться створити передній бізнес, щоб брехати про те, які залежності у вас є у pom.xml та ivy.xml. Для цього створіть підпроект для JAR-жиру лише там, де ви залежате від залежностей, і створіть другий косметичний підпроект, який ви використовуєте лише для публікації:

Опубліковано під ліцензією MIT, див. ЛІЦЕНЗІЯ

Про

Розгортайте жирні JAR. Перезапустіть процеси. (порт Codahale/Assembly-sbt)