maven-shade-pluginは何に使用されますか、そしてなぜJavaパッケージを再配置したいのですか?


281

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

私が見Mavenのドキュメント、しかし、私はこの文を理解することはできません。

「このプラグインは、依存関係を含むuber-jarにアーティファクトをパッケージ化し、一部の依存関係のパッケージをシェーディング(つまり、名前を変更)する機能を提供します。」

このページのドキュメントは、初心者にはあまり馴染みがないようです。

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

実例となる例/ユースケースへのポインタ(この場合にシェーディングが必要だった理由の説明-どのような問題が解決されているか)をいただければ幸いです。最後に、いつmaven-shade-pluginを使用すればよいですか?


16
「uber jar」というネーミングについては、ドイツ語との唯一の関連があります。「uber」は「over」を意味します。文字通り一緒にそれは「jar-over-all-other-jars」を意味しています。「シェーディング」は、衝突するクラスまたはリソースに必要な「パッケージの再割り当て」と同じです。
dma_k 2013

1
s/reallocation/relocation/上記のコメントで。
クリストファーシュルツ2017年

12
Uber jarは1つのリングのようなものです。1つのjarがすべてを支配し、1つのjarがそれらを見つけ、1つのjarがすべてを持ち込み、暗闇の中でそれらをバインドします。
Marti

回答:


342

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ます。他のバージョンのBarlib を使用できないと仮定します(APIの変更、または他の技術的な問題などのため)。私は単純に宣言する場合Bar:1.0としてFoo:Mavenの依存関係にあるのは、問題に陥ることが可能であるQuxプロジェクトが依存されてFooも、及びBar:2.0(およびそれが使用することはできませんBar:1.0ので、Quxニーズがで新しい機能を使用しますBar:2.0)。ここにジレンマがある:必要がありますQux使用Bar:1.0(これQuxのコードは動作しません)またはBar:2.0(これFooのコードは動作しませんか)?

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


5
ありがとう、それは大いに役立ちます。uber-jar内の依存関係と他のjarを隠すため、「シェーディング」と呼ばれますか?
2012年

6
名前の背後にある理由は本当にわかりませんが、フロントページから、「シェーディング」が依存関係の「非表示」を説明していることを示唆しているようです。オプションで、シェーディングされたJARにいくつかの依存関係を含めることができるため、シェードプラグインは正しいPOMを生成し、含まれている依存関係を削除します。陰影がこのプロセスを説明しているようです
Adrian Shum

1
@AdrianShum:シェードプラグインを使用せずに、uber jarを作成する方法を提案できますか?または、具体的には「Mavenの依存関係解決機能の台無し」を解決するにはどうすればよいですか?
Suraj Menon 2014年

3
@SurajMenon:udejarを作成する最も簡単な方法は、Shadeプラグインを使用することです。ただし、Assemblyプラグインを使用して、組み込みjar-with-dependency記述子を使用することもできます。uber-jarを使用した依存関係の解決の問題については、すでに私の回答で述べています:uber-jarを依存関係、期間として使用しないでください。もう少し詳しく:uber-jarを作成する前に、通常の依存関係を持つ通常のプロジェクトが必要です。その元のアーティファクトは、(uber-jarの代わりに)依存関係として使用する必要があるアーティファクトです
Adrian Shum 2014年

1
ちょっとした質問:機能しなくなりClass.forNameますか?
SOFe 2017年

64

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

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

ところで、私は実際にいくつかのelasticsearchのjarファイルを提供することに問題はありません。Mavenでそれを行う方法はわかりません。例えば、netty / jacksonをシェーディングしないバージョンを提供したくありません。たとえば、elasticsearchがそれらと密接に使用しているためです(たとえば、現在のバージョンを除く以前のバージョンの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の独自のクラスと一緒に再パッケージ化されます。プログラムのクラス、リソースなど、およびいくつかのメタデータを含む単なる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>

2

小さな警告

これは、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」ファイルを作成します。ファイルの内容は次のようになります(「@」文字の前のピリオドに注意してください):ルール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>

1
この別の提案をありがとう。これは私が探していたものではありませんでしたが、変更されることのないレガシーライブラリに1回限りのパッケージ翻訳を適用するための非常にシンプルで迅速なソリューションであることがわかりました。
Frelling 2016年

それぞれの出力の内容を比較することによって、そのような失敗の理由を理解しましたか?
三倍体

2

「シェーディングされた」jarの必要性の1つの例は、AWS Lambda関数だと思います。通常の.warファイルにあるような.jarのコレクション全体ではなく、1つのjarのみをアップロードできるようです。したがって、プロジェクトのすべての依存関係を持つ単一の.jarを作成すると、これを実行できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.