120

実行時とコンパイル時の違いと、この2つを区別する方法は理解していますが、コンパイル時と実行時の依存関係を区別する必要はありません。

私が窒息しているのはこれです:プログラムがコンパイル中に依存していた実行時に何かに依存しないようにするにはどうすればよいですか?私のJavaアプリがlog4jを使用している場合、コンパイル(log4j内からメンバーメソッドと統合して呼び出すコード)とランタイム(私のコードはlog4j内のコードで何が起こるかを完全に制御できません)のためにlog4j.jarファイルが必要です.jarが実行されます)。

IvyやMavenなどの依存関係解決ツールについて読んでいますが、これらのツールは、これら2つのタイプの依存関係を明確に区別しています。私はそれの必要性を理解していません。

誰かが簡単な「王の英語」タイプの説明を、できれば私のような貧しい樹液でも理解できる実際の例で説明できますか?

4

10 に答える 10

67

コンパイル時の依存関係は、通常、実行時に必要です。Mavenでは、compileスコープ付きの依存関係が実行時にクラスパスに追加されます(たとえば、戦争ではWEB-INF / libにコピーされます)。

ただし、厳密には必須ではありません。たとえば、特定のAPIに対してコンパイルして、コンパイル時の依存関係にする場合がありますが、実行時にAPIも含む実装を含めます。

プロジェクトがコンパイルするために特定の依存関係を必要とするが、対応するコードが実際には必要ないというフリンジケースがあるかもしれませんが、これらはまれです。

一方、コンパイル時に不要なランタイム依存関係を含めることは非常に一般的です。たとえば、Java EE 6アプリケーションを作成している場合は、Java EE 6 APIに対してコンパイルしますが、実行時には、任意のJavaEEコンテナーを使用できます。実装を提供するのはこのコンテナです。

リフレクションを使用すると、コンパイル時の依存関係を回避できます。たとえば、JDBCドライバはでロードでき、ロードされClass.forNameた実際のクラスは構成ファイルを介して構成できます。

于 2011-08-15T20:49:03.360 に答える
35

各Maven依存関係には、その依存関係を使用できるクラスパスを定義するスコープがあります。

プロジェクトのJARを作成する場合、依存関係は生成されたアーティファクトにバンドルされません。それらはコンパイルにのみ使用されます。(ただし、ビルドされたjarに依存関係をMavenに含めることはできます。Mavenを使用してjarに依存関係を含めるを参照してください) 。

Mavenを使用してWARまたはEARファイルを作成する場合、生成されたアーティファクトに依存関係をバンドルするようにMavenを構成できます。また、providedスコープを使用してWARファイルから特定の依存関係を除外するように構成することもできます。

最も一般的なスコープ— compile—プロジェクトで、コンパイルクラスパス、単体テストのコンパイルと実行のクラスパス、およびアプリケーションの実行時の最終的なランタイムクラスパスへの依存関係を利用できることを示します。Java EE Webアプリケーションでは、これは依存関係がデプロイされたアプリケーションにコピーされることを意味します。ただし、JARファイルでは、スコープが使用されるときに依存関係は含まれません。compile

runtimeスコープは、プロジェクトが単体テストの実行クラスパスとランタイム実行クラスパスに依存関係を利用できることを示しますが、compileスコープとは異なり、アプリケーションまたはその単体テストをコンパイルするときに依存関係を利用できません。ランタイム依存関係はデプロイされたアプリケーションにコピーされますが、コンパイル中は利用できません。これは、特定のライブラリに誤って依存しないようにするのに役立ちます。特定のロギング実装が使用されているが、ソースコードにロギングファサードのみをインポートしたいとします。スコープ付きの具象ログライブラリを含めるruntimeので、誤ってそれに依存することはありません。

最後に、providedスコープは、アプリケーションが実行されるコンテナーがユーザーに代わって依存関係を提供することを示します。Java EEアプリケーションでは、これは、依存関係がすでにサーブレットコンテナまたはアプリケーションサーバーのクラスパスにあり、デプロイされたアプリケーションにコピーされていないことを意味します。また、プロジェクトをコンパイルするためにこの依存関係が必要であることも意味します。

于 2014-09-26T03:41:03.153 に答える
9

コンパイル時に、実行時に必要になる可能性のある依存関係が必要です。ただし、多くのライブラリは、考えられるすべての依存関係なしで実行されます。つまり、4つの異なるXMLライブラリを使用できるライブラリですが、機能するのに必要なのは1つだけです。

多くのライブラリは、順番に他のライブラリを必要とします。これらのライブラリは、コンパイル時には必要ありませんが、実行時に必要です。つまり、コードが実際に実行されたときです。

于 2011-08-15T20:50:41.430 に答える
4

一般的にあなたは正しいです、そしておそらくそれは実行時とコンパイル時の依存関係が同一であるならば理想的な状況です。

このルールが正しくない場合の2つの例を示します。

クラスAがクラスBに依存し、クラスCに依存し、クラスDに依存している場合、Aはクラスであり、B、C、およびDは異なるサードパーティライブラリのクラスであり、コンパイル時にBとCのみが必要であり、Dも必要です。ランタイム。多くの場合、プログラムは動的なクラス読み込みを使用します。この場合、コンパイル時に使用しているライブラリによって動的にロードされるクラスは必要ありません。さらに、多くの場合、ライブラリは実行時に使用する実装を選択します。たとえば、SLF4JまたはCommons Loggingは、実行時にターゲットログの実装を変更できます。コンパイル時に必要なのはSSL4J自体だけです。

実行時よりもコンパイル時に多くの依存関係が必要な場合の反対の例。さまざまな環境またはオペレーティングシステムで動作する必要のあるアプリケーションを開発していると考えてください。コンパイル時にすべてのプラットフォーム固有のライブラリが必要であり、実行時に現在の環境に必要なライブラリのみが必要です。

私の説明がお役に立てば幸いです。

于 2011-08-15T20:51:00.133 に答える
3

通常、静的依存関係グラフは動的依存関係グラフのサブグラフです。たとえば、NDependの作成者によるこのブログエントリを参照してください。

とはいえ、いくつかの例外があります。主に、実行時に非表示になるコンパイラサポートを追加する依存関係です。たとえば、Lombokを介したコード生成、または(pluggable type-)CheckerFrameworkを介した追加のチェックの場合。

于 2011-09-06T17:23:16.643 に答える
3

実行時とコンパイル時の違いと、この2つを区別する方法は理解していますが、コンパイル時と実行時の依存関係を区別する必要はありません。

一般的なコンパイル時とランタイムの概念、およびMaven固有の依存関係compileruntimeスコープの依存関係は2つの非常に異なるものです。これらは同じフレームを持たないため、直接比較することはできません。一般的なコンパイルとランタイムの概念は広範ですが、Mavencompileruntimeスコープの概念は、具体的には、コンパイルまたは実行の時間に応じた依存関係の可用性/可視性に関するものです。
Mavenは何よりもjavac/javaラッパーであり、Javaには、指定するコンパイル時のクラスパスと、で指定javac -cp ... するランタイムクラスパスがあることを忘れないでくださいjava -cp ...。MavenスコープをJavaコンパイルとランタイムclassppathの両方に依存関係を追加する方法
と見なすことは間違いではありません(compilejavacおよびjava)Mavenruntimeスコープは、Javaランタイムclassppath()でのみ依存関係を追加する方法と見なすことができますjavac

私が窒息しているのはこれです:プログラムがコンパイル中に依存していた実行時に何かに依存しないようにするにはどうすればよいですか?

runtimeあなたが説明することは、compile範囲とは何の関係もありません。依存関係をコンパイル時に依存するように指定するスコープには、実行時ではなく、
より多くのように見えます。 コンパイルに依存関係が必要なために使用しますが、依存関係は環境によってすでに提供されているため、パッケージ化されたコンポーネント(JAR、WARなど)に含めたくありません。サーバーまたはその他に含めることができます。 Javaアプリケーションとして指定されたクラスパスのパスが開始されます。 provided

私のJavaアプリがlog4jを使用している場合、コンパイル(log4j内からメンバーメソッドと統合して呼び出すコード)とランタイム(私のコードはlog4j内のコードで何が起こるかを完全に制御できません)のためにlog4j.jarファイルが必要です.jarが実行されます)。

この場合はそうです。ただし、後で別のロギング実装(log4J 2、logbackなど)に切り替えることができるように、log4jの前のファサードとしてslf4jに依存するポータブルコードを作成する必要があるとします。
この場合、pomではslf4jをcompile依存関係として指定する必要があります(これがデフォルトです)が、log4jの依存関係を依存関係として指定しますruntime

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>...</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>...</version>
    <scope>runtime</scope>
</dependency>

このように、コンパイルされたコードでlog4jクラスを参照することはできませんでしたが、slf4jクラスを参照することはできます。
時間とともに2つの依存関係を指定した場合compile、コンパイルされたコードでlog4jクラスを参照することを妨げるものは何もないため、ロギング実装との望ましくない結合を作成する可能性があります。

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>...</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>...</version>
</dependency>

runtimeスコープの一般的な使用法は、JDBC依存関係宣言です。ポータブルコードを作成するには、クライアントコードが特定のDBMS依存関係(例:PostgreSQL JDBC依存関係)のクラスを参照することは望ましくありませんが、実行時にクラスを作成するために必要なのと同じように、アプリケーションに含める必要があります。 JDBCAPIはこのDBMSで動作します。

于 2018-08-30T07:24:45.193 に答える
2

あなたの質問に答える問題に遭遇しただけです。servlet-api.jarこれは私のWebプロジェクトの一時的な依存関係であり、コンパイル時と実行時の両方で必要です。しかしservlet-api.jar、Tomcatライブラリにも含まれています。

ここでの解決策はservlet-api.jar、Mavenをコンパイル時にのみ使用可能にし、warファイルにパッケージ化しないようにしてservlet-api.jar、Tomcatライブラリに含まれているものと衝突しないようにすることです。

これがコンパイル時とランタイムの依存関係を説明することを願っています。

于 2012-08-15T13:56:26.023 に答える
2

スコープは、runtimeプログラマーが抽象化やファサードを使用する代わりに、コード内の実装ライブラリに直接依存関係を追加することを防ぐためにあります。

つまり、インターフェイスの使用を強制します。

具体的な例:

1)チームはLog4jではなくSLF4Jを使用しています。プログラマーには、Log4jAPIではなくSLF4JAPIを使用してもらいたいと考えています。Log4jは、SLF4Jによって内部的にのみ使用されます。解決:

  • SLF4Jを通常のコンパイル時の依存関係として定義します
  • log4j-coreとlog4j-apiを実行時の依存関係として定義します。

2)アプリケーションがJDBCを使用してMySQLにアクセスしています。プログラマーには、MySQLドライバーの実装に対して直接ではなく、標準のJDBC抽象化に対してコーディングする必要があります。

  • mysql-connector-java(MySQL JDBCドライバー)を実行時の依存関係として定義します。

実行時の依存関係はコンパイル時に非表示になりますが(コードに「直接」依存関係がある場合はコンパイル時エラーが発生します)、実行時およびデプロイ可能なアーティファクト(WARファイル、SHADED jarファイルなど)の作成時に含まれます。

于 2020-01-29T10:13:46.997 に答える
1

コンパイル時に、依存関係から期待されるコントラクト/APIを有効にします。(例:ここでは、ブロードバンドインターネットプロバイダーとの契約に署名するだけです)実行時に、実際には依存関係を使用しています。(例:ここでは実際にブロードバンドインターネットを使用しています)

于 2011-08-15T20:55:05.717 に答える
0

「プログラムが実行時にコンパイル中に依存していたものに依存しないようにするにはどうすればよいのか」という質問に答えるために、注釈プロセッサの例を見てみましょう。

独自のアノテーションプロセッサを作成し、com.google.auto.service:auto-serviceを使用できるようにコンパイル時の依存関係があるとします@AutoService。この依存関係は、注釈プロセッサのコンパイルにのみ必要ですが、実行時には必要ありません。注釈を処理するために注釈プロセッサに依存する他のすべてのプロジェクトはcom.google.auto.service:auto-service実行時(コンパイル時またはその他の時間)に依存関係を必要としません。 。

これはあまり一般的ではありませんが、発生します。

于 2018-03-31T09:32:54.540 に答える