Le masquage des dépendances consiste à inclure et à renommer des dépendances (ce qui permet de déplacer les classes et de réécrire le code et les ressources affectés) afin de créer une copie privée que vous regroupez avec votre propre code .
Le concept est généralement associé aux uber-jars (aka jar fat ).
Il y a une certaine confusion à propos du terme , en raison de maven shade plugin, qui sous ce nom fait 2 choses (en citant leur propre page):
Ce plugin offre la possibilité de conditionner l'artefact dans un uber-jar, y compris ses dépendances, et de masquer - c'est-à-dire renommer - les packages de certaines des dépendances.
La partie ombrage est donc optionnelle: le plugin permet d’inclure des dépendances dans votre jar (fat jar), et éventuellement de renommer des dépendances (nuance) .
Ajout d' une autre source :
Ombrer une bibliothèque, c'est prendre les fichiers de contenu de cette bibliothèque, les mettre dans votre propre jarre et changer leur paquet . Cela diffère du packaging qui consiste simplement à expédier les fichiers de bibliothèques dans votre propre fichier JAR sans les déplacer dans un autre package.
Techniquement, les dépendances sont ombrées. Mais il est courant de se référer à une dépendance fat-jar-with-shaded en tant que "jar shaded", et si ce jar est un client d'un autre système, il peut être appelé "client ombré".
Voici le titre du numéro de Jira pour HBase que vous avez lié à votre question:
Publier un artefact client avec des dépendances ombrées
Donc, dans ce post, j'essaie de présenter les 2 concepts sans les mélanger.
Le bon
Uber-jars est souvent utilisé pour expédier une application sous forme de fichier unique (facilitant son déploiement et son exécution). Ils peuvent également être utilisés pour expédier des bibliothèques avec certaines (ou toutes) leurs dépendances ombrées , afin d'éviter les conflits lorsqu'elles sont utilisées par d'autres applications (qui peuvent utiliser différentes versions de ces bibliothèques).
Il y a plusieurs façons de construire uber-jars, mais maven-shade-plugin
va encore plus loin avec sa fonctionnalité de relocalisation de classe :
Si le fichier JAR uber est réutilisé en tant que dépendance d'un autre projet, l'inclusion directe de classes provenant des dépendances de l'artefact dans le fichier JAR uber peut entraîner des conflits de chargement de classe en raison de classes dupliquées sur le chemin de classe. Pour résoudre ce problème, il est possible de déplacer les classes incluses dans l'artefact ombré afin de créer une copie privée de leur code secondaire.
(Note historique: Les liens de jar Jar proposaient cette fonctionnalité de relocalisation auparavant)
Vous pouvez donc utiliser les dépendances de bibliothèque comme un détail d'implémentation , sauf si vous exposez des classes de ces bibliothèques dans votre API.
Supposons que j'ai un projet, ACME Quantanizer ™, qui fournit de la DecayingSyncQuantanizer
classe et dépend d'Apache commons-rng (car bien sûr, pour quantifier correctement, vous avez besoin d'un XorShift1024Star
, duh).
Si j'utilise le plugin shade maven pour produire un uber-jar, et que je regarde à l'intérieur, je vois les fichiers de classe suivants:
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
Maintenant, si j'utilise la fonctionnalité de déplacement de classe:
<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>
Le contenu de uber-jar ressemble à ceci:
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
Il ne s’agit pas seulement de renommer des fichiers, il réécrit du bytecode qui fait référence aux classes déplacées (ainsi, mes propres classes et classes communes sont toutes transformées).
De plus, le plug-in Shade générera également un nouveau POM ( dependency-reduced-pom.xml
) dans lequel les dépendances ombrées sont supprimées de la <dependencies>
section. Cela aide à utiliser le fichier jar ombré en tant que dépendance pour un autre projet. Vous pouvez donc publier ce fichier au lieu de celui de base, ou des deux (à l'aide d'un qualificateur pour le fichier ombré).
Cela peut donc être très utile ...
Le mauvais
... mais cela pose également un certain nombre de problèmes. L'agrégation de toutes les dépendances dans un seul "espace de noms" dans le fichier jar peut devenir compliquée et nécessiter de l'ombrage et des problèmes de ressources.
Par exemple: comment traiter les fichiers de ressources qui incluent des noms de classe ou de package? Les fichiers de ressources tels que les descripteurs de fournisseur de services dans lesquels tous vivent META-INF/services
?
Le plugin shade propose des transformateurs de ressources pouvant vous aider:
L'agrégation des classes / ressources de plusieurs artefacts dans un même JAR est simple tant qu'il n'y a pas de chevauchement. Sinon, une certaine logique pour fusionner les ressources de plusieurs JAR est requise. C’est là que les transformateurs de ressources entrent en jeu.
Mais cela reste compliqué et les problèmes sont presque impossibles à anticiper (vous les découvrez souvent à la dure dans la production). Voyez pourquoi nous avons arrêté de construire des pots de graisse .
Dans l’ensemble, le déploiement d’un pot de graisse en tant qu’application / service autonome est encore très courant; vous devez simplement être au courant des pièges et, pour certains d’entre eux, vous pourriez avoir besoin d’ ombrage ou d’autres astuces.
Le moche
Il y a beaucoup plus de problèmes difficiles (débogage, testabilité, compatibilité avec les chargeurs de classe OSGi & exotiques ...).
Mais plus important encore, lorsque vous produisez une bibliothèque, les divers problèmes que vous pensiez pouvoir contrôler devenaient maintenant infiniment plus compliqués, car votre fichier jar serait utilisé dans de nombreux contextes différents (contrairement à un fichier jar gros que vous déploieriez en tant qu'application / service autonome). dans un environnement contrôlé).
Par exemple, ElasticSearch ombrageait certaines dépendances dans les bocaux expédiés, mais ils ont décidé d'arrêter de le faire :
Avant la version 2.0, Elasticsearch était fourni sous forme de fichier JAR avec certaines dépendances communes (mais pas toutes) ombrées et conditionnées dans le même artefact. Cela a aidé les utilisateurs de Java intégrant Elasticsearch dans leurs propres applications à éviter les conflits de versions de modules tels que Guava, Joda, Jackson, etc. Bien entendu, il existait toujours une liste d'autres dépendances non ombrées telles que Lucene qui pouvaient toujours provoquer des conflits.
Malheureusement, l’ombrage est un processus complexe et sujet aux erreurs qui résout les problèmes de certaines personnes tout en créant des problèmes pour d’autres. Les ombrages empêchent les développeurs et les auteurs de plug-ins d'écrire et de déboguer le code correctement, car les packages sont renommés lors de la construction. Enfin, nous avions l'habitude de tester Elasticsearch sans ombrage, puis d'expédier le pot ombré, et nous n'aimons rien envoyer que nous ne testions pas.
Nous avons décidé d'expédier Elasticsearch sans ombrage à partir de la version 2.0.
S'il vous plaît noter qu'ils font aussi référence à des dépendances ombrées , pas jar ombré