367 Stimmen

Wofür wird das maven-shade-plugin verwendet, und warum sollten Sie Java-Pakete verlagern wollen?

Ich habe das maven-shade-plugin in der pom.xml von jemandem gefunden. Ich habe noch nie maven-shade-plugin verwendet (und ich bin ein Maven n00b), so dass ich versucht, den Grund für die Verwendung dieses und was es tut zu verstehen.

Ich habe mir die Maven-Dokumente Ich kann diese Aussage jedoch nicht nachvollziehen:

Dieses Plugin bietet die Möglichkeit, das Artefakt in ein Uber-Jar zu verpacken, einschließlich seiner Abhängigkeiten, und die Pakete einiger Abhängigkeiten zu schattieren - d.h. umzubenennen -.

Die Dokumentation auf dieser Seite scheint nicht sehr einsteigerfreundlich zu sein.

Was ist ein "Uber-Glas"? Warum sollte jemand ein solches Glas herstellen wollen? Welchen Sinn hat es, die Pakete der Abhängigkeiten umzubenennen? Ich habe versucht, die Beispiele auf der Apache-Seite des maven-shade-plugin durchzugehen, wie z.B. "Selecting contents for Uber Jar", aber ich kann immer noch nicht verstehen, was mit "shading" erreicht werden soll.

Für Hinweise auf anschauliche Beispiele/Anwendungsfälle (mit einer Erklärung, warum die Schattierung in diesem Fall erforderlich war - welches Problem wird damit gelöst) wären wir dankbar. Und schließlich, wann sollte ich das maven-shade-plugin verwenden?

81voto

Tom Punkte 1487

Ich habe mich vor kurzem gefragt, warum elasticsearch einige (aber nicht alle) seiner Abhängigkeiten abschattet und verlagert. Hier ist eine Erklärung vom Betreuer des Projekts, @kimchy :

Die Schattierung ist beabsichtigt, die schattierten Bibliotheken, die wir in elasticsearch verwenden, sind in jeder Hinsicht Teil von elasticsearch, die verwendete Version ist eng mit dem verknüpft, was elasticsearch offenlegt und wie es die Bibliothek verwendet, basierend auf den Interna, wie die Bibliothek funktioniert (und das ändert sich zwischen den Versionen), netty und guava sind gute Beispiele.

Übrigens habe ich kein Problem damit, mehrere Jars von Elasticsearch zur Verfügung zu stellen, eines mit Lucene ohne Schatten, und eines mit Lucene mit Schatten. Ich bin mir allerdings nicht sicher, wie ich das mit Maven machen soll. Ich möchte keine Version zur Verfügung stellen, die z.B. netty/jackson nicht schattiert, weil elasticsearch sehr eng mit ihnen verbunden ist (z.B. wird die Verwendung der kommenden Pufferring-Verbesserung mit jeder früheren Version von netty, außer der aktuellen, mehr Speicher verbrauchen, als wenn man deutlich weniger verwendet).

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

Und eine weitere hier von drewr :

Die Schattierung ist wichtig, um unsere Abhängigkeiten (insbesondere netty, lucene, guava) in der Nähe unseres Codes zu halten, damit wir ein Problem beheben können, auch wenn der Upstream-Anbieter hinterherhinkt. Es ist möglich, dass wir modularisierte Versionen des Codes verteilen werden, was bei Ihrem speziellen Problem helfen würde (#2091 zum Beispiel), aber wir können die schattierten Abhängigkeiten zu diesem Zeitpunkt nicht einfach entfernen. Sie können eine lokale Version von ES für Ihre Zwecke erstellen, bis es eine bessere Lösung gibt.

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

Das ist also ein Anwendungsfall. Zur Veranschaulichung ein Beispiel, wie das maven-shade-plugin in der pom.xml von elasticsearch (v0.90.5) verwendet wird. Die artifactSet::include Zeilen weisen es an, welche Abhängigkeiten in das Uber-JAR gezogen werden sollen (im Grunde werden sie entpackt und zusammen mit den elasticsearch-eigenen Klassen neu verpackt, wenn das Ziel-Elasticsearch-Jar erzeugt wird. (Falls Sie es noch nicht wussten, eine JAR-Datei ist einfach eine ZIP-Datei, die die Programmklassen, Ressourcen usw. und einige Metadaten enthält. Sie können eine entpacken, um zu sehen, wie sie zusammengesetzt ist).

En relocations::relocation Zeilen sind ähnlich, mit dem Unterschied, dass sie in jedem Fall auch die angegebenen Ersetzungen auf die Klassen der Abhängigkeit anwenden - in diesem Fall, indem sie sie unter org.elasticsearch.common .

Schließlich wird die filters Abschnitt schließt einige Dinge aus dem Ziel-JAR aus, die dort nicht enthalten sein sollten - wie JAR-Metadaten, Ant-Build-Dateien, Textdateien usw., die mit einigen Abhängigkeiten verpackt sind, aber nicht in ein Uber-JAR gehören.

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

8voto

atom88 Punkte 1229

Ein Beispiel für die Notwendigkeit eines "schattierten" Jars ist eine AWS Lambda-Funktion. Sie scheinen Sie nur 1 Jar hochladen zu lassen, nicht eine ganze Sammlung von Jars, wie Sie sie in einer typischen War-Datei finden würden. Durch das Erstellen einer einzelnen JAR-Datei mit allen Abhängigkeiten des Projekts können Sie dies tun.

3voto

nadavy Punkte 1725

Kleine Warnung

Obwohl das nicht beschreibt, warum man das maven-shade-plugin verwenden möchte (da die ausgewählte Antwort es ziemlich gut beschreibt), möchte ich anmerken, dass ich Probleme damit hatte. Es änderte das JAR (denn das ist es, was es tut) und es verursachte Regression in meiner Software.

Also, anstatt dieses (oder das Maven-Jarjar-Plugin) zu verwenden, habe ich das JarJar-Binary verwendet, das ohne Probleme zu funktionieren scheint.

Ich poste hier meine Lösung, da ich einige Zeit gebraucht habe, um eine vernünftige Lösung zu finden.


JarJar's JAR-Datei herunterladen

Sie können die Jar-Datei hier herunterladen: https://code.google.com/p/jarjar/ Im linken Menü finden Sie einen Link zum Herunterladen der Datei.


Wie man JarJar verwendet, um Klassen eines JAR von einem Paket in ein anderes zu verschieben

In diesem Beispiel ändern wir das Paket von "com.fasterxml.jackson" in "io.kuku.dependencies.com.fasterxml.jackson". - Das Quell-JAR heißt "jackson-databind-2.6.4.jar" und das neue modifizierte (Ziel-)JAR heißt "kuku-jackson-databind-2.6.4.jar". - Die JAR-Datei "jarjar" hat die Version 1.4

  1. Erstellen Sie eine Datei "rules.txt". Der Inhalt der Datei sollte wie folgt aussehen (achten Sie auf den Punkt vor dem "@"-Zeichen): Regel com.fasterxml.jackson.** io.kuku.dependencies.com.fasterxml.jackson.@1

  2. Führen Sie den folgenden Befehl aus: java -jar jarjar-1.4.jar process rules.txt jackson-databind-2.6.4.jar kuku-jackson-databind-2.6.4.jar


Installation der geänderten JARs in das lokale Repository

In diesem Fall installiere ich 3 Dateien, die sich unter "c: \my -jars\"-Ordner.

mvn install:install-file -Dfile= C:\my -Gläser \kuku -jackson-annotations-2.6.4.jar -DgroupId=io.kuku.dependencies -DartifactId=kuku-jackson-annotations -Dversion=2.6.4 -Dpackaging=jar

mvn install:install-file -Dfile= C:\my -Gläser \kuku -jackson-core-2.6.4.jar -DgroupId=io.kuku.dependencies -DartifactId=kuku-jackson-core -Dversion=2.6.4 -Dpackaging=jar

mvn install:install-file -Dfile= C:\my -Gläser \kuku -jackson-databind-2.6.4.jar -DgroupId=io.kuku.dependencies -DartifactId=kuku-jackson-annotations -Dversion=2.6.4 -Dpackaging=jar


Verwendung der geänderten JARs in der pom-Datei des Projekts

In diesem Beispiel ist dies das Element "dependencies" in der pom-Datei des Projekts:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X