web-dev-qa-db-ja.com

Java:クラスパスJVM上の複数のリソースのどれが必要ですか?

クラスパスに同じ名前のファイルが複数ある場合(たとえば、複数の.jar with log4j.properties)、JVMが1つを選択するために従う規則は何ですか?

47
Ondra Žižka

-classpathオプションを使用してリソース(通常はjarファイル)が指定される順序で指定されます。クラスパスの「以前の」リソースは、それらの後に指定されたリソースよりも優先されます。これは、アプリケーションのマニフェストファイルでも設定でき、-classpathオプションを指定する必要はありません。マニフェストファイルの操作方法について これらの記事 を確認することをお勧めします。

「クラスの見つけ方」の詳細な説明は、 here にあります。ここで、JAR-class-path ClassesのセクションJARファイル検索のロジックについて説明します。

51
mouser

ClassLoaderは、リソースの場所を決定します(ClassLoader JavaDocから取得)。

ClassLoaderクラスは、委任モデルを使用してクラスとリソースを検索します。 ClassLoaderの各インスタンスには、関連する親クラスローダーがあります。クラスまたはリソースの検索が要求されると、ClassLoaderインスタンスは、クラスまたはリソース自体を検索する前に、クラスまたはリソースの検索を親クラスローダーに委任します。 「ブートストラップクラスローダー」と呼ばれる仮想マシンの組み込みクラスローダーは、それ自体に親はありませんが、ClassLoaderインスタンスの親として機能する場合があります。

したがって、コードのどこでClass#getResourceまたはClass#getResourceAsStreamが呼び出されると、これが起こります(Class.Javaから取得)

public Java.net.URL getResource(String name) {
    name = resolveName(name);
    ClassLoader cl = getClassLoader0();
    if (cl==null) {
        // A system class.
        return ClassLoader.getSystemResource(name);
    }
    return cl.getResource(name);
}

ClassLoader.Java:

public URL getResource(String name) {
    URL url;
    if (parent != null) {
        url = parent.getResource(name);
    } else {
        url = getBootstrapResource(name);
    }
    if (url == null) {
        url = findResource(name);
    }
    return url;
}

classLoader#findResourceは、実際にはClassLoader実装によって上書きされます。これは、アプリケーションサーバー、Tomcatで動作が異なること、またはjarファイルから実行している場合、現在の環境のClassLoader実装に依存することを意味します。

ここ は、特定のケースで内部の状況を追跡するために使用できる例です。

8
emboss

クラスパスが、たとえばフォルダー内のすべてのjarであり、そのうちの1つ(またはいくつか)に優先順位を付けたい場合、これは機能しないという実証済みのケースに貢献しています:

ウィンドウズ:

bin/prioritized.jar;bin/*

Linux:

bin/prioritized.jar:bin/*

最初のパスbin/prioritized.jarは、ワイルドカードを持つ2番目のパスが独自のスコープにそれを含むため、無視されるようです。これは、指定されたクラスパスの順序を事実上破壊するものです。

したがって、複数のリソースに優先順位を付けるには(Java 10.0.1でテスト済み)、重複しないスコープに配置する必要があります。そうすれば、それらは機能します。

0
S-t-x