クラスパスに同じ名前のファイルが複数ある場合(たとえば、複数の.jar
with log4j.properties
)、JVMが1つを選択するために従う規則は何ですか?
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実装に依存することを意味します。
ここ は、特定のケースで内部の状況を追跡するために使用できる例です。
クラスパスが、たとえばフォルダー内のすべてのjarであり、そのうちの1つ(またはいくつか)に優先順位を付けたい場合、これは機能しないという実証済みのケースに貢献しています:
ウィンドウズ:
bin/prioritized.jar;bin/*
Linux:
bin/prioritized.jar:bin/*
最初のパスbin/prioritized.jarは、ワイルドカードを持つ2番目のパスが独自のスコープにそれを含むため、無視されるようです。これは、指定されたクラスパスの順序を事実上破壊するものです。
したがって、複数のリソースに優先順位を付けるには(Java 10.0.1でテスト済み)、重複しないスコープに配置する必要があります。そうすれば、それらは機能します。