web-dev-qa-db-ja.com

「シェーディング」Java依存関係とは何ですか?

JVM開発者はこちら。最近、私はIRCチャットルームや、自分のオフィスで、いわゆる「shaded」についての冗談を目にしました。 Javaライブラリ。使用のコンテキストは次のようになります。

"このように、XYZの「シェーディング」クライアントが提供されます。"

完璧な例は このHBaseのJiraの問題 :「シェーディングされた依存関係を持つクライアントアーティファクトを公開する

だから私は尋ねます:shadedJARとは何ですか、それは「シェーディング」されているとはどういう意味ですか?

89
smeeb

依存関係のシェーディングは、プロセスの依存関係(したがって、クラスの再配置と影響を受けるバイトコードとリソースの書き換え)をにバンドルするプライベートコピーを作成するプロセスですあなた自身のコードと一緒に

この概念は通常、 ber-jars (aka fat jars )に関連付けられています。

単一の名前で 2つのこと (独自のページを引用)を実行するmavenシェードプラグインのため、用語について混乱があります

このプラグインは、依存関係を含むuber-jarにアーティファクトをパッケージ化する機能とshade-つまり、rename-一部の依存関係のパッケージを提供します。

したがって、シェーディング部分は実際にはオプションです:プラグインにより、jar(ファットjar)に依存関係を含めることができ、オプションでdependencyの名前を変更(シェーディング)できます。

追加 別のソース

ライブラリをシェーディングするには、そのライブラリのコンテンツファイルを取得し、それらを独自のjarファイル、に入れ、パッケージを変更します。これは、ライブラリファイルを別のパッケージに再配置することなく、独自のjarに同梱するだけのパッケージとは異なります。

技術的に言えば、依存関係は網掛けされています。ただし、fat-jar-with-shaded-dependenciesを「シェーディングされたjar」と呼ぶことは一般的であり、そのjarが別のシステムのクライアントである場合は、「シェーディングされたクライアント」と呼ぶことができます。

これは、質問でリンクしたHBaseのJira課題のtitleです。

シェーディングされた依存関係を持つクライアントアーティファクトを公開する

したがって、この投稿では、2つの概念を混同することなく提示しようとしています。

いいもの

Uber-jarは多くの場合、アプリケーションを単一のファイルとして配布するために使用されます(展開と実行が簡単になります)。また、他のアプリケーション(これらのライブラリの異なるバージョンを使用する可能性がある)で使用される場合の競合を回避するために、依存関係の一部(またはすべて)shadedとともにライブラリを出荷するためにも使用できます。

Uber-jarをビルドするにはいくつかの方法がありますが、- maven-shade-pluginclass relocation 機能でさらに一歩進んでいます:

Uber JARが他のプロジェクトの依存関係として再利用される場合、uber JARにアーティファクトの依存関係のクラスを直接含めると、クラスパスでクラスが重複するため、クラスの読み込みが競合する可能性があります。この問題に対処するには、陰影付きのアーティファクトに含まれるクラスを再配置して、バイトコードのプライベートコピーを作成します。

(過去のメモ: Jar Jar Links 以前にその再配置機能を提供していました)

そのため、APIでこれらのライブラリのクラスを公開しない限り、ライブラリの依存関係を実装の詳細にすることができます。

DecayingSyncQuantanizerクラスを提供するプロジェクトACME Quantanizer™があり、Apache commons-rngに依存しているとしましょう(_もちろんは、XorShift1024Starが必要であることを正しく量子化するために、まあ)。

Shade mavenプラグインを使用してuber-jarを生成し、内部を見ると、次のクラスファイルが表示されます。

com/acme/DecayingSyncQuantanizer.class
org/Apache/commons/rng/RandomProviderState.class
org/Apache/commons/rng/RestorableUniformRandomProvider.class
...
org/Apache/commons/rng/core/source64/XorShift1024Star.class
org/Apache/commons/rng/core/util/NumberFactory.class

クラス再配置機能を使用する場合:

<plugin>
  <groupId>org.Apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.0.0</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <relocations>
          <relocation>
            <pattern>org.Apache.commons</pattern>
            <shadedPattern>com.acme.shaded.apachecommons</shadedPattern>
          </relocation>
        </relocations>
      </configuration>
    </execution>
  </executions>
</plugin>

Uber-jarの内容は次のようになります。

com/acme/DecayingSyncQuantanizer.class
com/acme/shaded/apachecommons/rng/RandomProviderState.class
com/acme/shaded/apachecommons/rng/RestorableUniformRandomProvider.class
...
com/acme/shaded/apachecommons/rng/core/source64/XorShift1024Star.class
com/acme/shaded/apachecommons/rng/core/util/NumberFactory.class

それは単にファイルの名前を変更するだけでなく、再配置されたクラスを参照するバイトコードを書き換えます(したがって、自分のクラスとcommons-rngクラスはすべて変換されます)。

さらに、Shadeプラグインは新しいPOM(dependency-reduced-pom.xml)も生成します。この場合、影付きの依存関係は<dependencies>セクションから削除されます。これは、影付きのjarを別のプロジェクトの依存関係として使用するのに役立ちます。したがって、ベースのjarの代わりにそのjarを公開できます またはその両方 (色付きのjarの修飾子を使用)。

とても便利です...

悪い人

...しかしそれはまた多くの問題を引き起こします。 jar内のすべての依存関係を単一の「名前空間」に集約すると、面倒になり、シェーディングとリソースの変更が必要になる場合があります。

例:クラス名またはパッケージ名を含むリソースファイルをどのように処理するか?すべてがMETA-INF/servicesの下にあるサービスプロバイダー記述子などのリソースファイル

シェードプラグインは リソーストランスフォーマー を提供し、それを支援します。

複数のアーティファクトから1つのuber JARにクラス/リソースを集約することは、重複がない限り簡単です。それ以外の場合は、いくつかのJARからのリソースをマージするためのある種のロジックが必要です。これが リソーストランスフォーマー の始まりです。

しかし、それでも面倒で、問題を予測することはほとんど不可能です(本番環境で問題を発見することが非常に多いです)。 why-we-stopped-building-fat-jars を参照してください。

概して、スタンドアロンのアプリ/サービスとしてファットjarをデプロイすることは依然として非常に一般的であり、問​​題点に注意する必要があるだけであり、その一部についてはshadingまたはその他のトリックが必要になる場合があります。

ぶさいく

さらに多くの難しい問題があります(デバッグ、テスト容易性、OSGiとの互換性、エキゾチックなクラスローダー...)。

しかし、さらに重要なことは、ライブラリを作成するとき、jarがさまざまなコンテキストで使用されるため(スタンドアロンのアプリ/サービスとしてデプロイする太いjarとは異なり)、制御できると考えていたさまざまな問題が非常に複雑になります。制御された環境で)。

たとえば、ElasticSearchは出荷されたjarの一部の依存関係をシェーディングするために使用していましたが、 彼らはそれをやめることにしました

バージョン2.0より前は、Elasticsearchは、同じアーティファクト内でシェーディングおよびパッケージ化された一部(すべてではない)の共通依存関係を持つJARとして提供されていました。これはJava Guava、Joda、Jacksonなどのモジュールのバージョン競合を回避するために独自のアプリケーションにElasticsearchを埋め込むユーザーに役立ちました。もちろん、Luceneのような他の影のない依存関係のリストはまだありましたそれでも競合が発生する可能性があります。
残念ながら、シェーディングは複雑でエラーが発生しやすいプロセスであり、他の人のために問題を作成しながら、一部の人にとっては問題を解決しました。シェーディングは、ビルド中にパッケージの名前が変更されるため、開発者やプラグインの作成者がコードを適切に記述してデバッグすることを非常に困難にします。最後に、以前はシェーディングされていないElasticsearchをテストしてからシェーディングされたjarを出荷していましたが、テストしていないものは出荷したくありません。
2.0以降、シェーディングなしでElasticsearchを出荷することを決定しました。

シェーディングされたjarではなく、シェーディングされた依存関係を参照していることに注意してください。

107
Hugues M.

シェーディングされたjarファイルの作成を実際に担当するソフトウェアの助けを借りて、質問に答えましょう...少なくともmavenを使用する場合。

Apache Maven Shade Plugin ホームページから取得:

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

シェーディングされたjar、別名uber-jar、別名fat jarには、デフォルトでJavaアプリケーションを実行するために必要なすべての依存関係が含まれるため、クラスパスに追加の依存関係を置く必要はありません。正しいJavaアプリケーションを実行するためのバージョン。色付きのjarはデプロイメント/クラスパスの問題を回避するのに役立ちますが、元のアプリケーションのjarよりもはるかに大きく、jar hellを回避するのに役立ちません。 。

7
Jesko R.