30

40〜50のOSSパッケージに依存する大規模な(> 500,000 LOC)Javaシステムがあります。システムはAntで構築されており、現在、依存関係の管理は手動で処理されています。依存関係を自動化するためにIvyやMavenを調査しています。昨年、Mavenをビルド自動化システムと見なし、Mavenのアーキテクチャに一致するようにシステムを完全に再構築する必要があるため、拒否しました。今、私は依存関係管理タスクだけを自動化しようとしています。

Ivyでいくつかの実験を行いましたが、問題が発生しました。たとえば、ActiveMQを依存関係として指定し、依存関係の指定にMavenリポジトリ内のPOMを使用するようにIvyに指示すると、Ivyは、必要がないことがわかっている一連のパッケージ(Jetty、Derby、Geronimoなど)を取得します。 ActiveMQを使用します。

ivysettings.xmlでusepoms="false"を設定すると、activemq.jarのみがフェッチされますが、それはIvyの目的を無効にし、手動で作成された依存関係仕様を持つ単純なjarフェッチャーに委任するようです。

ここにはもっと大きな問題があります。これは、Windowsでは「DLL地獄」と呼ばれていたものです。場合によっては、2つの直接的な第1レベルの依存関係が、同じ推移的な依存関係の異なるバージョン(log4j.jarなど)を指すことがあります。クラスパスに含めることができるlog4j.jarは1つだけであるため、依存関係の解決には、システム内のすべてのクライアントと互換性のあるバージョンを手動で決定することが含まれます。

結局のところ、各パッケージの依存関係仕様(POM)の品質に帰着すると思います。ActiveMQの場合、スコープ宣言がないため、ActiveMQへの参照は、不要であることがわかっている依存関係を手動で除外しない限り、すべての依存関係をダウンロードします。

log4jの場合、自動依存関係解決では、log4jのすべてのクライアント(log4jに依存する他のパッケージ)がlog4jの以前のすべてのバージョンに対して検証し、POMに互換性のあるlog4jバージョンの範囲(またはリスト)を提供する必要があります。それは多分質問するには多すぎます。

これは現在の状況ですか、それとも何かが足りないのですか?

4

8 に答える 8

11

あなたの言うことは絶対に正しい

すべては、各パッケージの依存関係の仕様 (POM) の品質にかかっていると思います。

追加する唯一のことは、POM またはその他の形式のメタデータを出発点として表示することです。たとえば、ActiveMQ がすべての依存関係を提供することは非常に便利ですが、それが実際にプロジェクトに適しているかどうかを選択するのはあなた次第です。

結局のところ、log4j のバージョンを考慮に入れても、外部の依存関係にバージョンを選択させるか、それとも自分にとって適切であることがわかっているバージョンを選択させるでしょうか?


依存関係を調整する方法については、Ivy でできることは次のとおりです。

不要なパッケージ

Ivy は、ActiveMQ を使用するだけでは必要ないことがわかっている一連のパッケージ (Jetty、Derby、Geronimo など) を取得します。

これは通常、アプリケーションのモジュール性が低いために発生します。たとえば、アプリケーションの一部には Jetty が必要ですが、使用しなくてもこの推移的な依存関係が発生します。

おそらく、アイビーの除外メカニズムを調べたいと思うでしょう:

<dependency name="A" rev="1.0">
  <exclude module="B"/>
</dependency>

依存関係のバージョン

クラスパスに入れることができる log4j.jar は 1 つのみであるため、依存関係の解決では、システム内のすべてのクライアントと互換性のあるバージョンを手動で決定する必要があります。

私の読み違いかもしれませんが、Ivy のコンフリクト解決には手作業の要素はありません。デフォルトの競合マネージャのリストがあります:

  • all : この競合マネージャは、すべてのリビジョンを選択して競合を解決します。NoConflictManager とも呼ばれ、すべてのモジュールを削除します。
  • latest-time : このコンフリクト マネージャは、「最新」のリビジョンのみを選択します。最新のリビジョンは、最新のものとして定義されます。最新の時間は計算にコストがかかることに注意してください。可能な場合は、最新のリビジョンを優先してください。
  • latest-revision : このコンフリクト マネージャーは、「最新」のリビジョンのみを選択します。最新のリビジョンは、リビジョンの文字列比較によって定義されます。
  • latest-compatible : このコンフリクト マネージャは、コンフリクト内の最新バージョンを選択します。これにより、互換性のある一連の依存関係が生じる可能性があります。これは、最終的に、このコンフリクト マネージャーが (厳密なコンフリクト マネージャーのように) コンフリクトを許可しないことを意味します。
  • strict : このコンフリクト マネージャーは、コンフリクトが見つかるたびに例外をスローします (つまり、ビルドの失敗を引き起こします)。

必要に応じて、独自の競合マネージャーを提供できます

于 2009-09-21T18:59:55.837 に答える
5

それはほとんどそれです。Maven 依存関係システム (Ivy は多かれ少なかれ従います) は、依存関係に必要なメタデータを適切に追加することを個々のプロジェクトに任せています。ほとんどはしません。

その道を行く場合は、除外の設定に時間を費やすことを期待してください.

OSGi を推奨するポスターに対して、OP は Maven 用にビルド システムを再構築する気はないと述べました。OSGi に準拠するようにアプリケーションを再構築したいとは思わないでしょう。さらに、OSGi 準拠の OSS プロジェクトの多く (そして期待するほど多くはありません) は、Maven よりも悪いメタデータを持っています。

于 2009-09-21T18:57:11.570 に答える
5

リストする依存関係のうち、以下はpomのように定義されています(Mavenブックの関連セクションも参照してoptionalください)activemq-core

  • org.apache.derby:ダービー
  • org.apache.geronimo.specs:geronimo-jta_1.0.1B_spec

Jetty への直接的な依存関係は見られなかったので、オプションの依存関係の 1 つから推移的に含まれている可能性があります。

Maven では、オプションの依存関係は自動的に処理されます。基本的に、オプションとして宣言されている依存関係はすべて、使用するために pom で再宣言する必要があります。上記のリンクのドキュメントから:

オプションの依存関係は、(何らかの理由で) プロジェクトをサブモジュールに分割することが実際には不可能な場合に使用されます。依存関係の一部はプロジェクトの特定の機能にのみ使用され、その機能が使用されていない場合は必要ないという考え方です。理想的には、そのような機能は、コア機能プロジェクトに依存するサブモジュールに分割されます...この新しいサブプロジェクトは、サブプロジェクトの機能を使用することにした場合にそれらすべてが必要になるため、オプションではない依存関係のみを持ちます。

ただし、プロジェクトは (何らかの理由で) 分割できないため、これらの依存関係はオプションとして宣言されています。ユーザーがオプションの依存関係に関連する機能を使用したい場合は、独自のプロジェクトでそのオプションの依存関係を再宣言する必要があります。これは、この状況を処理する最も明確な方法ではありませんが、オプションの依存関係と依存関係の除外の両方が一時的な解決策です。

オプションの依存関係を無視するように Ivy を構成できるかどうかはわかりませんが、依存関係を除外するように構成できます。例えば:

<dependency name="A" rev="1.0">
  <exclude module="B"/>
</dependency>

これは完全に満足できるものではありません。Ivy はオプションの依存関係をサポートしている可能性があります (さらに調べて、何かが見つかったら更新します) が、除外メカニズムにより、少なくともそれらを管理できます。


質問の最後の部分について。Maven は log4j の依存バージョンを解決し、バージョンに互換性がある場合は、リストされたバージョンの「最も近い」バージョンを自動的に選択します。

依存メカニズムの紹介から:

  • 依存関係の仲介 - これにより、アーティファクトの複数のバージョンが検出されたときに使用される依存関係のバージョンが決定されます。現在、Maven 2.0 は「最も近い定義」の使用のみをサポートしています。これは、依存関係のツリーでプロジェクトに最も近い依存関係のバージョンを使用することを意味します。プロジェクトの POM で明示的に宣言することにより、常にバージョンを保証できます。依存関係ツリーで 2 つの依存関係バージョンが同じ深さにある場合、Maven 2.0.8 まではどちらが優先されるかは定義されていませんでしたが、Maven 2.0.9 以降では宣言内の順序が重要であることに注意してください。つまり、最初の宣言が優先されます。

    • 「最も近い定義」は、使用されるバージョンが依存関係のツリーでプロジェクトに最も近いものになることを意味します。A、B、および C の依存関係が A -> B -> C -> D 2.0 および A -> E -> D 1.0 として定義されている場合、A を構築するときに D 1.0 が使用されます。 Eは短いです。A で D 2.0 への依存関係を明示的に追加して、D 2.0 の使用を強制することができます。

バージョンに互換性がない場合、依存関係の解決よりも大きな問題があります。Ivy も同様のモデルで動作していると思いますが、私は専門家ではありません。

于 2009-09-21T19:07:09.773 に答える
4

これがまさに現状だと思います。OSGiと Java 1.7 用に提案された新しいパッケージング システム (その議論はすでに結論に達していますか?) は、少なくともライブラリの異なるバージョンに依存する問題を修正する試みですが、私はしません。彼らはあなたの問題を今すぐ解決できると思います。

于 2009-09-21T18:48:21.903 に答える
3

私は現在 Ivy を使用して、120 以上の OSS および独自のライブラリを複数のプロジェクト (スタンドアロン、依存関係) で管理しています。2005 年 (Ivy がまだ Jayasoft に所属していたとき) に、統合パッケージごとに ivy.xml ファイルを作成することにしました (または作成する必要がありました)。

最大の利点は、さまざまな構成を完全に制御できることです。これはやり過ぎに聞こえるかもしれませんが、私たちのビルド システムは 4 年以上にわたって安定して動作しており、新しいライブラリの追加は通常 5 分の作業で済みます。

于 2009-09-21T22:47:49.917 に答える
2

「これが現状ですか?」

OSGi ではありません。OSGi コンテナーとバンドルを参照することをお勧めします。バンドルは jar ファイルに似ていますが、そのバージョンの詳細を示すメタ データと、必要な関連バンドルのバージョンをサポートします (属性を META-INF ファイルに入れることにより)。したがって、log4j バンドルはそのバージョンを示し、依存バンドルは必要な log4j のバージョンを詳細に示します。

さらに、非階層型のクラスローダ メカニズムがサポートされているため、log4j の複数のバージョンをロードでき、さまざまなバンドルでそれらのさまざまなバージョンを指定してバインドできます。

Javaworld には、ここに非常に優れた紹介があります。

于 2009-09-21T18:49:16.503 に答える
0

依存性注入の全体的な考え方があります-それは常にプログラムを再構築する必要につながるでしょう。GUICEがこの点で優れているということについて、私はいくつかの騒ぎを聞いています。デプロイメントの観点では、jnlpを介して元のプロジェクトからフェッチされた依存関係.jarを使用してビルドした.jarのみをデプロイすることにかなりの成功を収めました。この背後にあるビルドシステムには、依存関係の新しいバージョンの手動追跡とビルドシステムの更新が含まれていました。

于 2009-09-22T06:10:42.607 に答える
-5

「これが現状か」

はい。

これがオープンソースのトレードオフです。

クローズド ソース フレームワーク (つまり、.Net) は、これらすべてを解決してくれます。

オープンソース ソリューションとは、常にそれを解決 (および解決) しなければならないことを意味します。

事前に構築された構成をいくつか見つけて、それらを最新の状態に保つために誰かに支払うことができる場合があります。たとえば、Red Hat Enterprise Linux の使用を選択できます。彼らがサポートするものに正確に固執すれば(そしてそれ以上のものは何もない)、構成は解決されます。

ただし、要件を満たすパッケージ化された構成がない可能性は十分にあります。

于 2009-09-21T18:46:25.693 に答える