322

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

Mavenのドキュメントを見ましたが、このステートメントを理解できません。

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

このページのドキュメントは、初心者向けではないようです。

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

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

4

4 に答える 4

386

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

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

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

補足:Mavenの依存関係解決機能を台無しにするため、uber-jarをMavenの依存関係として使用することは避けてください。通常、uber-jarは、実際のデプロイまたは手動配布用の最終アーティファクト用にのみ作成されますが、Mavenリポジトリーに配置するためには作成されません。


更新:「依存関係のパッケージの名前を変更する意味は何ですか?」という質問の一部に答えていないことに気づきました。これは、同様の質問をしている人々に役立つと思われる簡単な更新です。

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

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

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

于 2012-11-29T06:58:47.667 に答える
72

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

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

ところで、私は実際にいくつかのelasticsearchのjarファイルを提供することに問題はありません。1つはシェーディングされていないluceneを使用し、もう1つはシェーディングされたLuceneを使用しています。ただし、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つのユースケースです。説明に役立つ例として、以下は、elasticsearchのpom.xml(v0.90.5)でmaven-shade-pluginがどのように使用されるかを示しています。行はartifactSet::include、uber JARにプルする依存関係を指示します(基本的に、ターゲットのelasticsearch jarが生成されるときに、それらは解凍され、elasticsearch自体のクラスと一緒に再パッケージ化されます(これをまだ知らなかった場合、JARファイルはプログラムのクラス、リソースなど、およびいくつかのメタデータを含むZIPファイルだけです。1つを抽出して、どのようにまとめられているかを確認できます。)

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

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

<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>
于 2013-10-15T16:51:13.130 に答える
5

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

于 2020-03-04T00:25:16.527 に答える
2

小さな警告

それは、maven-shade-pluginを使用したい理由を説明していませんが(選択した回答はそれをかなりよく説明しているため)、問題があったことに注意したいと思います。それはJARを変更し(それが行っているので)、それは私のソフトウェアにリグレッションを引き起こしました。

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

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


ダウンロード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」ファイルを作成します。ファイルの内容は次のようになります(「@」文字の前のピリオドに注意してください):rulecom.fasterxml.jackson。**io.kuku.dependencies.com.fasterxml.jackson。@1

  2. 次のコマンドを実行します。java-jarjarjar-1.4.jarprocess 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>
于 2016-01-13T13:55:56.083 に答える