Затінення залежностей - це процес включення та перейменування залежностей (таким чином переміщення класів та перезапис уражених байт-кодів та ресурсів) для створення приватної копії, яку ви поєднуєте разом із власним кодом .
Поняття, як правило, асоціюється з uber-банками (ака- жировими банками ).
Існує деяка плутанина щодо цього терміна через плагін Maven shadow, який під цією назвою робить 2 речі (цитуючи власну сторінку):
Цей плагін забезпечує можливість упаковки артефакту в uber-jar, включаючи його залежності, і відтіняти - тобто перейменувати - пакети деяких залежностей.
Таким чином, затінювальна частина насправді необов'язкова: плагін дозволяє включати залежності у вашу банку (жирова банка), а також необов'язково перейменовувати (відтінок) залежності .
Додавання іншого джерела :
Shade-бібліотека - це взяти файли вмісту згаданої бібліотеки, помістити їх у власну банку і змінити пакет . Це відрізняється від упаковки, яка просто пересилає файли бібліотек у вашу власну банку, не переставляючи їх до іншого пакету.
Технічно кажучи, залежності затінені. Але звичайно називати залежність жиру з затіненою залежністю як "затінену банку", і якщо ця банку є клієнтом іншої системи, її можна називати "затіненим клієнтом".
Ось назва випуску Jira для HBase, який ви пов’язали у своєму запитанні:
Опублікуйте артефакт клієнта із затіненими залежностями
Тож у цій публікації я намагаюся представити 2 поняття, не плутаючи їх.
Добрий
Uber-банки часто використовуються для доставки програми у вигляді одного файлу (полегшує розгортання та запуск). Вони також можуть використовуватися для передачі бібліотек разом із затіненими деякими (або всіма) залежностями , щоб уникнути конфліктів при використанні інших програм (які можуть використовувати різні версії цих бібліотек).
Існує декілька способів побудови uber-jar, але це maven-shade-plugin
іде ще на крок далі з його функцією перенесення класу :
Якщо JAR uber повторно використовується як залежність від якогось іншого проекту, безпосередньо включення класів від залежностей артефакту в JAB uber може спричинити конфлікти завантаження класів через дублювання класів на шляху класу. Для вирішення цього питання можна перенести класи, які включаються до затіненого артефакту, щоб створити приватну копію їхнього байтового коду.
(Історична примітка: Jar Jar Links пропонував цю функцію переїзду раніше)
Таким чином, ви можете перетворити залежності вашої бібліотеки в деталі реалізації , якщо ви не виставляєте класи з цих бібліотек у своєму API.
Скажімо, у мене є проект ACME Quantanizer ™, який забезпечує DecayingSyncQuantanizer
клас, і залежить від Apache commons-rng (тому що, звичайно, для належного квантування вам потрібен XorShift1024Star
дух).
Якщо я використовую плагін Maven Shadow для створення uber-jar, і я заглядаю всередину, я бачу ці файли класу:
com/acme/DecayingSyncQuantanizer.class
org/apache/commons/rng/RandomProviderState.class
org/apache/commons/rng/RestorableUniformRandomProvider.class
...
org/apache/commons/rng/core/source64/XorShift1024Star.class
org/apache/commons/rng/core/util/NumberFactory.class
Тепер, якщо я використовую функцію перенесення класу:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.apache.commons</pattern>
<shadedPattern>com.acme.shaded.apachecommons</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
Зміст uber-jar виглядає приблизно так:
com/acme/DecayingSyncQuantanizer.class
com/acme/shaded/apachecommons/rng/RandomProviderState.class
com/acme/shaded/apachecommons/rng/RestorableUniformRandomProvider.class
...
com/acme/shaded/apachecommons/rng/core/source64/XorShift1024Star.class
com/acme/shaded/apachecommons/rng/core/util/NumberFactory.class
Це не просто перейменування файлів, він переписує байт-код, на який посилаються переміщені класи (так, мої власні класи & commons-rng класи трансформуються).
Крім того, плагін Shade також буде генерувати новий POM ( dependency-reduced-pom.xml
), в якому затінені залежності видаляються з <dependencies>
розділу. Це допомагає використовувати затінену банку як залежність від іншого проекту. Таким чином, ви можете опублікувати цю банку замість основної або обох (використовуючи класифікатор для затіненої банки).
Тож це може бути дуже корисно ...
Поганий
... але це також викликає ряд питань. Агрегація всіх залежностей в єдиний "простір імен" всередині банку може заплутатися і вимагати затінення та безладдя з ресурсами.
Наприклад: як поводитися з файлами ресурсів, які містять назви класів або пакетів? Файли ресурсів, такі як дескриптори постачальника послуг, під якими живуть усі META-INF/services
?
Плагін відтінку пропонує трансформатори ресурсів, які можуть допомогти у цьому:
Агрегація класів / ресурсів з декількох артефактів в один JAR Uber пряма вперед, доки не буде перекриття. В іншому випадку потрібна певна логіка для об'єднання ресурсів з декількох JAR. Саме тут починають працювати трансформатори ресурсів .
Але це все ще безладно, і проблем майже неможливо передбачити (досить часто ви виявляєте проблеми важким шляхом у виробництві). Подивіться, чому ми зупинилися, будуючи жирові банки .
Загалом, розгортання жирової баночки як окремого додатка / послуги все ще дуже поширене, вам просто потрібно знати про ґетчі, а для деяких із них вам може знадобитися затінення або інші хитрощі.
Потворний
Є багато складніших питань (налагодження, перевіряти, сумісність з OSGi та екзотичними завантажувачами класів ...).
Але що ще важливіше, коли ви створюєте бібліотеку, різні питання, які, на вашу думку, ви могли б контролювати, стають нескінченно складнішими, тому що ваша баночка буде використовуватися в багатьох різних контекстах (на відміну від жирової банки, яку ви розгортаєте як окремий додаток / послугу у контрольованому середовищі).
Наприклад, ElasticSearch використовував для затінення деяких залежностей у поставлених банках, але вони вирішили припинити це :
До версії 2.0 Elasticsearch пропонувався як JAR з деякими (але не всіма) загальними залежностями, затіненими та упакованими в один артефакт. Це допомогло користувачам Java, які вбудовували Elasticsearch у свої власні програми, щоб уникнути конфліктів версій таких модулів, як Guava, Joda, Jackson і т. Д. Звичайно, все ж був список інших нестабільних залежностей, таких як Lucene, які все ще можуть викликати конфлікти.
На жаль, затінення - це складний процес, схильний до помилок, який вирішує проблеми для одних людей, створюючи проблеми для інших. Затінення ускладнює розробникам та авторам плагінів правильне написання та налагодження коду, оскільки пакети перейменовані під час збирання. Нарешті, ми тестували Elasticsearch в незатіненому вигляді, потім перевозили затінену банку, і нам не подобається відправляти все, що ми не тестуємо.
Ми вирішили поставити Elasticsearch без затінення від 2,0 і далі.
Зверніть увагу, вони теж відносяться до затінених залежностей , а не до затінених баночок