web-dev-qa-db-ja.com

maven-shade-pluginは何に使用されますか?Javaパッケージを再配置する理由は何ですか?

誰かのpom.xmlでmaven-shade-pluginが使用されていることがわかりました。私は以前にmaven-shade-pluginを使用したことがないので(Maven n00bです)、これを使用する理由とその機能を理解しようとしました。

Maven docs を見ましたが、このステートメントを理解できません:

「このプラグインは、アーティファクトを依存関係を含めてuber-jarにパッケージ化する機能と、一部の依存関係のパッケージをシェードする(つまり、名前を変更する)機能を提供します。」このページのドキュメントは初心者向けではないようです。

「ユーバージャー」とは何ですか?なぜ誰かが作りたいのでしょうか?依存関係のパッケージの名前を変更する意味は何ですか? 「Uber Jarのコンテンツを選択する」など、maven-shade-plugin Apacheページの例を試してみましたが、「シェーディング」で何が達成されているのかまだ理解できません。

例示的な例/ユースケースへのポインタ(この場合にシェーディングが必要な理由の説明-それが解決する問題は何か)が評価されます。最後に、いつmaven-shade-pluginを使用する必要がありますか?

248
nonbeing

要するに、Uber JARはすべてを含むJARです。

通常、Mavenでは、依存関係管理に依存しています。アーティファクトには、それ自体のクラス/リソースのみが含まれます。 Mavenは、プロジェクトがいつビルドされるかに応じて、プロジェクトが生成するすべてのアーティファクト(JARなど)を見つける責任があります。

Uber-jarは、すべての依存関係を取得し、依存関係のコンテンツを抽出し、プロジェクト自体のクラス/リソースと共に1つの大きなJARに入れます。このようなuber-jarを使用すると、アプリを実行するのに大量の小さなJARの代わりに1つの大きなJARしか必要ないため、実行が簡単です。また、場合によっては配布が容易になります。

ただの補足です。 Mavenの依存関係解決機能を台無しにしているため、Mavenの依存関係としてuber-jarを使用しないでください。通常、実際のデプロイメントまたは手動配布の最終成果物に対してのみuber-jarを作成しますが、Mavenリポジトリーに置くためには作成しません。


更新:質問の一部に答えていないことを発見しました:「依存関係のパッケージの名前を変更する意味は何ですか?」。ここにいくつかの簡単な更新があり、うまくいけば同様の質問がある人々を助けるでしょう。

展開を容易にするためにuber-jarを作成することは、シェードプラグインの1つのユースケースです。パッケージの名前変更を伴う他の一般的なユースケースもあります。

たとえば、私はFooライブラリの特定のバージョン(1.0など)に依存するBarライブラリを開発しています。 (APIの変更やその他の技術的な問題などにより)Bar libの他のバージョンを使用できないと仮定します。 MavenでFooの依存関係としてBar:1.0を単純に宣言すると、問題に陥る可能性があります:QuxプロジェクトはFooに依存し、またBar:2.0に依存します(そしてQuxBar:1.0で新しい機能を使用する必要があるため、Bar:2.0を使用できません)。ジレンマは次のとおりです。QuxBar:1.0Quxのコードは機能しません)またはBar:2.0Fooのコードは機能しません)を使用する必要がありますか?

この問題を解決するために、Fooの開発者は、Bar:1.0 jarのすべてのクラスがBar jarに埋め込まれ、埋め込みFooクラスのパッケージがcom.barからcom.foo.barに変更されるように、シェードプラグインを使用してBarの使用の名前を変更することを選択できます。そうすることで、QuxBar:2.0に安全に依存するようになります。これは、FooBarに依存しなくなり、別のパッケージにある「変更された」Barのコピーを使用しているためです。

299
Adrian Shum

私は最近、elasticsearchが依存関係の一部(すべてではない)をシェーディングおよび再配置する理由を疑問に思っていました。以下はプロジェクトのメンテナー、@ kimchyからの説明です:

シェーディング部分は意図的なものであり、elasticsearchで使用するシェーディングされたライブラリはelasticsearchのすべての意図と目的の部分に使用され、使用されるバージョンはelasticsearchが公開するものと、ライブラリの動作の内部に基づいてライブラリを使用する方法に密接に結び付けられています(そしてバージョン間の変更)、netty、およびguavaは素晴らしい例です。

ところで、私は実際にいくつかのjarのelasticsearchを提供することに問題はありません。しかし、Mavenでそれを行う方法はわかりません。例えば、elasticsearchが持つ非常によく似た使用法のために、例えばnetty/jacksonをシェーディングしないバージョンを提供したくありません(例えば、現在のバージョンを除く、以前のバージョンのnetty実際にかなり少ないメモリを使用する場合と比較して、より多くのメモリを使用します)。

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

そして、ここから別のdrewr

シェーディングは、依存関係(特にnetty、lucene、guava)をコードの近くに維持して、アップストリームプロバイダーが遅れた場合でも問題を修正できるようにするために重要です。特定の問題(#2091など)に役立つモジュール化されたバージョンのコードを配布することは可能ですが、現時点では影付きの依存関係を単純に削除することはできません。より良い解決策が見つかるまで、目的に合わせてESのローカルバージョンをビルドできます。

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

だから、それは1つのユースケースです。実例として、maven-shade-pluginがelasticsearchのpom.xml(v0.90.5)でどのように使用されるかを以下に示します。 artifactSet::include行は、uber JARに取り込む依存関係を指示します(基本的に、ターゲットのelasticsearch jarが生成されると、それらはElasticsearchの独自のクラスと一緒に解凍および再パッケージ化されます(これをまだ知らない場合は、JARファイルは、プログラムのクラス、リソースなど、およびいくつかのメタデータを含む単なるZipファイルです。1つを抽出して、それがどのように組み合わされるかを確認できます。

relocations::relocation行は似ていますが、それぞれの場合に、依存関係のクラスに指定された置換を適用します。この場合、それらをorg.elasticsearch.commonの下に置きます。

最後に、filtersセクションは、JARメタデータ、Antビルドファイル、テキストファイルなど、いくつかの依存関係でパッケージ化されているが、Uber JARに属さないものをターゲットJARから除外します。 。

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

小さな警告

Maven-shade-pluginを使用したい理由は説明されていませんが(選択した回答ではかなりよく説明されているため)、問題がありました。 JARが変更されたため(それが実行しているため)、ソフトウェアのリグレッションが発生しました。

そのため、これ(またはmaven-jarjar-plugin)を使用する代わりに、問題なく動作するように見えるJarJarのバイナリを使用しました。

適切な解決策を見つけるのに時間がかかったので、ここに自分の解決策を投稿しています。


Downlaod JarJarのJARファイル

Jarはここからダウンロードできます。 https://code.google.com/p/jarjar/ 左側のメニューには、ダウンロードするためのリンクがあります。


JARのクラスをあるパッケージから別のパッケージに再配置するためにJarJarを使用する方法

この例では、パッケージを「com.fasterxml.jackson」から「io.kuku.dependencies.com.fasterxml.jackson」に変更します。 -ソースJARは「jackson-databind-2.6.4.jar」と呼ばれ、新しく変更された(ターゲット)JARは「kuku-jackson-databind-2.6.4.jar」と呼ばれます。 -「jarjar」JARファイルはバージョン1.4にあります

  1. 「rules.txt」ファイルを作成します。ファイルの内容は次のとおりです(「@」文字の前のピリオドに注意してください):rule com.fasterxml.jackson。** io.kuku.dependencies.com.fasterxml.jackson。@ 1

  2. 次のコマンドを実行します。Java -jar jarjar-1.4.jar process rules.txt jackson-databind-2.6.4.jar kuku-jackson-databind-2.6.4.jar


変更したJARをローカルリポジトリにインストールする

この場合、「c:\ my-jars \」フォルダーにある3つのファイルをインストールします。

mvn install:install-file -Dfile = C:\ my-jars\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-jars\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-jars\kuku-jackson-databind-2.6.4.jar -DgroupId = io.kuku.dependencies -DartifactId = kuku-jackson-annotations -Dversion = 2.6.4- Dpackaging = jar


プロジェクトのPOMで変更されたJARを使用する

この例では、これはプロジェクト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>
2
nadavy