À quoi sert le plugin maven-shade-et pourquoi voudriez-vous déplacer des paquets Java?


J'ai trouvé le plugin maven-shade-utilisé dans le pom de quelqu'un.XML. Je n'ai jamais utilisé maven-shade-plugin avant (et je suis un Maven n00b) donc j'ai essayé de comprendre la raison de l'utiliser et ce qu'il fait.

J'ai regardé le Maven docs , mais je ne peux pas comprendre cette déclaration:

"Ce plugin permet d'empaqueter l'artefact dans un uber-jar, y compris ses dépendances et d'ombrer - c'est - à-dire de renommer-les paquets de certaines des dépendances." Le la documentation sur la page ne semble pas très conviviale pour les débutants.

Qu'est Ce qu'un "uber pot?"Pourquoi quelqu'un voudrait-il le faire? Quel est l'intérêt de renommer les paquets des dépendances? J'ai essayé de parcourir les exemples sur la page apache maven-shade-plugin tels que "Sélection du contenu pour Uber Jar", mais je ne comprends toujours pas ce qui est accompli avec " ombrage."

Tous les pointeurs vers des exemples/cas d'utilisation illustratifs (avec une explication des raisons pour lesquelles l'ombrage était requis dans ce cas-quel problème résout-il) serait apprécié. Enfin, quand dois-je utiliser le plugin maven-shade?

Author: Lii, 2012-11-29

3 answers

Uber JAR, en bref, est un POT contenant tout.

Normalement dans Maven, nous nous appuyons sur la gestion des dépendances. Un artefact ne contient que les classes / ressources de lui-même. Maven sera responsable de trouver tous les artefacts (pots, etc.) que le projet dépend du moment où le projet est construit.

Un uber-jar est quelque chose qui prend toutes les dépendances, extrait le contenu des dépendances et les met avec les classes/ressources du projet lui-même, dans un grand JAR. En ayant un tel uber-jar, il est facile à exécuter, car vous n'aurez besoin que d'un seul grand POT au lieu de tonnes de petits POTs pour exécuter votre application. Il facilite également la distribution dans certains cas.

Juste une note de côté. Évitez d'utiliser uber-jar comme dépendance Maven, car cela ruine la fonctionnalité de résolution des dépendances de Maven. Normalement, nous créons uber-jar uniquement pour l'artefact final pour le déploiement réel ou pour la distribution manuelle, mais pas pour la mise dans le référentiel Maven.


Mise à jour: J'ai je viens de découvrir que je n'ai pas répondu à une partie de la question: "Quel est l'intérêt de renommer les paquets des dépendances?". Voici quelques brèves mises à jour et, espérons-le, aideront les personnes ayant une question similaire.

Créer uber-jar pour faciliter le déploiement est un cas d'utilisation du plugin shade. Il existe également d'autres cas d'utilisation courants impliquant un changement de nom de package.

Par exemple, je développe la bibliothèque Foo, qui dépend d'une version spécifique (par exemple 1.0) de la bibliothèque Bar. En supposant que je ne puisse pas utiliser une autre version de Bar lib (parce que l'API change, ou d'autres problèmes techniques, etc.). Si je déclare simplement Bar:1.0 comme dépendance de Foo dans Maven, il est possible de tomber dans un problème: Un projet Qux dépend de Foo, et aussi Bar:2.0 (et il ne peut pas utiliser Bar:1.0 car Qux doit utiliser une nouvelle fonctionnalité dans Bar:2.0). Voici le dilemme: Qux devrait-il utiliser Bar:1.0 (quel code Qux ne fonctionnera pas) ou Bar:2.0 (quel code Foo ne fonctionnera pas)?

Afin de résoudre ce problème, le développeur de Foo pouvez choisir d'utiliser l'ombre plugin pour renommer son utilisation de Bar, de sorte que toutes les classes dans Bar:1.0 jar sont incorporés dans Foo jar, et le paquet de l'embarqué Bar classes est modifié à partir de com.bar à com.foo.bar. Ce faisant, Qux peut dépendre en toute sécurité de Bar:2.0 car maintenant Foo ne dépend plus de Bar, et il utilise sa propre copie de "altered" Bar située dans un autre paquet.

 269
Author: Adrian Shum, 2016-02-12 02:20:20

Je me demandais récemment pourquoi elasticsearch nuance et relocalise quelques-unes (mais pas toutes) de ses dépendances. Voici une explication du responsable du projet, @kimchy:

La partie d'ombrage est intentionnelle, les bibliothèques ombrées que nous utilisons dans elasticsearch font partie de l'intention et du but d'elasticsearch, la version utilisée est étroitement liée à ce que elasticsearch expose et à la façon dont elle utilise la bibliothèque en fonction du fonctionnement interne de la bibliothèque (et cela change entre les versions), netty et goyave sont d'excellents exemples.

Btw, je n'ai aucun problème à fournir plusieurs pots d'elasticsearch, un avec lucene non ombré, et un avec Lucene ombré. Je ne sais pas comment le faire avec maven cependant. Je ne veux pas fournir une version qui n'ombrage pas netty / jackson par exemple, en raison de l'utilisation intime profonde qu'elasticsearch a avec eux (par exemple, en utilisant l'amélioration de bufferring à venir avec n'importe quelle version précédente de netty à l'exception de l'actuel utilisera en fait plus de mémoire que d'utiliser considérablement moins).

-- https://github.com/elasticsearch/elasticsearch/issues/2091#issuecomment-7156766

Et un autre ici de drewr :

L'ombrage est important pour garder nos dépendances (notamment netty, lucene, goyava) proches de notre code afin que nous puissions résoudre un problème même si le fournisseur amont est à la traîne. Il est possible que nous le fassions des versions modularisées distribuées du code, ce qui aiderait à résoudre votre problème particulier (#2091 par exemple), mais nous ne pouvons pas simplement supprimer les dépendances ombrées pour le moment. Vous pouvez créer une version locale d'ES à vos fins jusqu'à ce qu'il y ait une meilleure solution.

-- https://github.com/elasticsearch/elasticsearch/pull/3244#issuecomment-20125452

Donc, c'est un cas d'utilisation. En ce qui concerne un exemple illustratif, voici comment maven-shade-plugin est utilisé dans elasticsearch est pom.xml (v0.90. 5). Les lignes artifactSet::include lui indiquent quelles dépendances tirer dans le pot uber (fondamentalement, elles sont décompressées et réemballées aux côtés des propres classes d'elasticsearch lorsque le pot elasticsearch cible est produit. (Au cas où vous ne le saviez pas déjà, un fichier JAR est juste un fichier ZIP qui contient les classes, les ressources, etc. du programme. et certaines métadonnées. Vous pouvez en extraire un pour voir comment il est assemblé.)

Les lignes relocations::relocation sont similaires, sauf que dans chaque cas ils appliquent également les substitutions spécifiées aux classes de la dépendance - dans ce cas, en les ramenant sous org.elasticsearch.common.

Enfin, la section filters exclut certaines choses du JAR cible qui ne devraient pas y être - telles que les métadonnées JAR, les fichiers de génération ant, les fichiers texte, etc. qui sont empaquetés avec certaines dépendances, mais qui n'appartiennent pas à un pot uber.

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.1</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <minimizeJar>true</minimizeJar>
            <artifactSet>
                <includes>
                    <include>com.google.guava:guava</include>
                    <include>net.sf.trove4j:trove4j</include>
                    <include>org.mvel:mvel2</include>
                    <include>com.fasterxml.jackson.core:jackson-core</include>
                    <include>com.fasterxml.jackson.dataformat:jackson-dataformat-smile</include>
                    <include>com.fasterxml.jackson.dataformat:jackson-dataformat-yaml</include>
                    <include>joda-time:joda-time</include>
                    <include>io.netty:netty</include>
                    <include>com.ning:compress-lzf</include>
                </includes>
            </artifactSet>
            <relocations>
                <relocation>
                    <pattern>com.google.common</pattern>
                    <shadedPattern>org.elasticsearch.common</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>gnu.trove</pattern>
                    <shadedPattern>org.elasticsearch.common.trove</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>jsr166y</pattern>
                    <shadedPattern>org.elasticsearch.common.util.concurrent.jsr166y</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>jsr166e</pattern>
                    <shadedPattern>org.elasticsearch.common.util.concurrent.jsr166e</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>org.mvel2</pattern>
                    <shadedPattern>org.elasticsearch.common.mvel2</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>com.fasterxml.jackson</pattern>
                    <shadedPattern>org.elasticsearch.common.jackson</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>org.joda</pattern>
                    <shadedPattern>org.elasticsearch.common.joda</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>org.jboss.netty</pattern>
                    <shadedPattern>org.elasticsearch.common.netty</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>com.ning.compress</pattern>
                    <shadedPattern>org.elasticsearch.common.compress</shadedPattern>
                </relocation>
            </relocations>
            <filters>
                <filter>
                    <artifact>*:*</artifact>
                    <excludes>
                        <exclude>META-INF/license/**</exclude>
                        <exclude>META-INF/*</exclude>
                        <exclude>META-INF/maven/**</exclude>
                        <exclude>LICENSE</exclude>
                        <exclude>NOTICE</exclude>
                        <exclude>/*.txt</exclude>
                        <exclude>build.properties</exclude>
                    </excludes>
                </filter>
            </filters>
        </configuration>
    </plugin>
</plugins>
 55
Author: Tom, 2017-05-23 11:55:07

Petit avertissement

Bien que ce ne soit pas décrire pourquoi on aimerait utiliser le maven-shade-plugin (puisque la réponse sélectionnée le décrit assez bien), je voudrais noter que j'ai eu des problèmes avec cela. Cela a changé le POT (depuis ce qu'il fait) et cela a provoqué une régression dans mon logiciel.

Donc, au lieu d'utiliser ceci (ou le plugin maven-jarjar), j'ai utilisé le binaire de JarJar qui semble fonctionner sans problème.

Je poste ici ma solution depuis que cela m'a pris peu de temps pour trouver une solution convenable.


Télécharger le fichier JAR de JarJar

Vous pouvez télécharger le pot à partir d'ici: https://code.google.com/p/jarjar / Dans le menu de gauche, vous avez un lien pour le télécharger.


Comment utiliser JarJar pour déplacer les classes d'un JAR d'un paquet à un autre

Dans cet exemple, nous allons changer le paquet de "com.fasterxml.jackson " à "io. kuku. dependencies. com. fasterxml. jackson". - Le POT source est appelé "jackson-databind-2.6.4.jar " et le nouveau JAR modifié (cible) s'appelle "kuku-jackson-databind-2.6.4.pot". - Le fichier JAR" jarjar " est en version 1.4

  1. Créer un " règles.txt " fichier. Le contenu du fichier doit être (regardez le point avant le caractère'@'): règle de com.fasterxml.Jackson.** io.kuku.dependencies.com.fasterxml.jackson.@1

  2. Exécutez la commande suivante: java-jar jarjar-1.4.règles de processus jar.txt jackson-databind-2.6.4.pot kuku-jackson-databind-2.6.4.jar


Installation des fichiers JAR modifiés dans le référentiel local

Dans ce cas, j'installe 3 fichiers situés sur "c:\my-jars \" dossier.

Mvn install:install-fichier -Dfile=C:\mon-pots\kuku-jackson-annotations-2.6.4.jar-DgroupId=io.kuku.les dépendances-DartifactId=kuku-jackson-annotations-Dversion=2.6.4-Dpackaging=jar

Mvn install:install-fichier -Dfile=C:\mon-pots\kuku-jackson-core-2.6.4.jar-DgroupId=io.kuku.dépendance - DartifactId=kuku-jackson-core-Dversion=2.6.4-Dpackaging=jar

Mvn install:install-fichier -Dfile=C:\mon-pots\kuku-jackson-databind-2.6.4.jar-DgroupId=io.kuku.les dépendances-DartifactId=kuku-jackson-annotations-Dversion=2.6.4-Dpackaging=jar


Utilisation des JARs modifiés dans le pom du projet

Dans cet exemple, il s'agit de l'élément" dependencies " dans les projets pom:

<dependencies>
    <!-- ================================================== -->
    <!-- kuku JARs -->
    <!-- ================================================== -->
    <dependency>
        <groupId>io.kuku.dependencies</groupId>
        <artifactId>kuku-jackson-annotations</artifactId>
        <version>2.6.4</version>
    </dependency>
    <dependency>
        <groupId>io.kuku.dependencies</groupId>
        <artifactId>kuku-jackson-core</artifactId>
        <version>2.6.4</version>
    </dependency>
    <dependency>
        <groupId>io.kuku.dependencies</groupId>
        <artifactId>kuku-jackson-databind</artifactId>
        <version>2.6.4</version>
    </dependency>
</dependencies>
 1
Author: nadavy, 2016-01-13 13:55:56