7

Java 8 はこちら。

次のように定義されたクラスを持つ、widgetMaven 座標を持つライブラリの古いバージョンがあるとします。widgetmakers:widget:1.0.4

public class Widget {
    private String meow;

    // constructor, getters, setters, etc.
}

年が経ちます。このwidgetライブラリの管理者は、 aWidgetは決してmeowではなく、実際には であるべきであると判断していbarkます。そのため、Maven 座標widgetmakers:widget:2.0.0を使用しWidgetて次のような新しいリリースが作成されます。

public class Widget {
    private Bark bark;

    // constructor, getters, setters, etc.
}

それでは、アプリをビルドしmyappます。そして、すべての依存関係の最新の安定したバージョンを使用したいので、依存関係を次のように宣言します (内build.gradle):

dependencies {
    compile (
        ,'org.slf4j:slf4j-api:1.7.20'
        ,'org.slf4j:slf4j-simple:1.7.20'
        ,'bupo:fizzbuzz:3.7.14'
        ,'commons-cli:commons-cli:1.2'
        ,'widgetmakers:widget:2.0.0'
    )
}

ここで、この (架空の)fizzbuzzライブラリが常にwidgetライブラリの 1.x バージョンに依存しているとしWidgetましょうmeow

widgetそのため、コンパイル クラスパスで の 2 つのバージョンを指定しています。

  1. widgetmakers:widget:1.0.4これは、fizzbuzzライブラリの依存関係としてライブラリによって取り込まれます。と
  2. widgetmakers:widget:2.0.0私が直接参照している

Widgetしたがって、明らかに、最初にクラスロードされる のバージョンに応じて、Widget#meowまたは のいずれかになりますWidget#bark

Gradle は、ここで私を支援するための機能を提供していますか? 同じクラスの複数のバージョンを取り込みfizzbuzz、古いバージョンの を使用するようにクラスを構成Widgetし、新しいバージョンを使用するように私のクラスを構成する方法はありますか? そうでない場合、私が考えることができる唯一の解決策は次のとおりです。

  1. ある種のシェーディングおよび/またはファットジャーベースのソリューションを達成できるかもしれません。おそらく、すべての依存関係をパッケージとして取り込み、myapp/bin異なるバージョンプレフィックスを付けます。確かに、ここで明確な解決策はわかりませんが、何かが実現可能であると確信しています(ただし、完全にハック/厄介です)。または...
  2. 依存関係グラフ全体を注意深く調べて、すべての推移的な依存関係が互いに競合していないことを確認してください。この場合、これはfizzbuzzメンテナーにプルリクエストを送信して最新widgetバージョンにアップグレードするか、残念ながらダウングレードmyappして古いwidgetバージョンを使用することを意味します。

しかし、Gradle (これまでのところ) は私にとって魔法のようなものでした。だから私は尋ねます:ここで私を利用できるGradleマジックはありますか?

4

4 に答える 4

7

私はMavenの人なので、Gradleの詳細はわかりませんが、とにかくこれはより一般的です。基本的に 2 つのオプションがあります (どちらもハックです)。

  1. クラスローダーの魔法。どういうわけか、ビルド システムに 2 つのバージョンのライブラリをロードするように説得する必要があります (それでうまくいきます)。次に、実行時に、古いバージョンを使用するクラスを、古いバージョンを持つ ClassLoader でロードします。私はこれをしましたが、それは苦痛です。(OSGI のようなツールは、この苦痛の一部を取り除くかもしれません)
  2. パッケージの陰影。古いバージョンのライブラリ B を使用するライブラリ A を再パッケージ化して、B が実際には A 内にあるようにしますが、B 固有のパッケージ プレフィックスを付けます。これは一般的な方法です。たとえば、Springは独自のバージョンの asm を出荷しています。Maven 側では、maven-shade-pluginがこれを行います。おそらく Gradle に相当するものがあります。または、Jar 操作の 800 ポンドのゴリラであるProGuardを使用することもできます。
于 2016-04-29T14:27:26.120 に答える
2

Gradle は依存関係を含むクラスパスを設定するだけで、依存関係とその推移的な依存関係をカプセル化するための独自のランタイムは提供しません。実行時にアクティブなバージョンは、クラスローディング規則に従ったバージョンになります。これは、クラスを含むクラスパス順序の最初の jar であると私は信じています。OSGI は、このような状況に対処できるランタイムを提供しており、今後のモジュール システムも同様です。

編集: Bjorn は、異なるバージョンで競合を解決しようとするという点で正しいです。戦略に基づいてクラスパスをコンパイルするため、ファイルに依存関係を配置する順序は重要ではありません。ただし、クラス名ごとに1つのクラスしか取得できないため、OPの問題は解決されません

于 2016-04-29T14:18:28.730 に答える
0

他の点では等しい座標を持つ異なるバージョンのライブラリがある場合、Gradles の競合解決メカニズムが機能します。

デフォルトの解決方法は、要求された最新バージョンのライブラリを使用することです。依存関係グラフで同じライブラリの複数のバージョンを取得することはありません。

実行時に同じライブラリの異なるバージョンが本当に必要な場合は、間違いなく可能な ClassLoader マジックを実行するか、ライブラリの 1 つまたは両方に対してシェーディングを行う必要があります。

競合の解決に関して、Gradle にはデフォルトの最新の戦略と、依存関係グラフに異なるバージョンがあり、ビルド ファイルでバージョンの競合を明示的に解決する必要がある場合に失敗する失敗戦略が組み込まれています。

于 2016-04-29T14:56:35.737 に答える