3

ClassLoader が特定の条件下でのみ機能するリソースを解決しようとしている状況に苦しんでいます。

ユースケースは次のとおりです。自動受け入れテストのために、IBM Rational Functional Tester を JBehave と組み合わせて使用​​しています。JBehave は、テストをプレーン テキストのストーリー ファイルとして指定します。これらのストーリー ファイルは、「Given Stories」と呼ばれる他のストーリー ファイルを参照できます。JBehave はExecutorServiceを使用して、潜在的にマルチスレッド化されたストーリーを実行します。JBehave は (ClassLoader.getResourceAsStream を使用して) テキスト ファイルを問題なくロードできますが、ExecutorService から起動されたスレッドで同じファイルを見つけることができません。

実際の ClassLoader はContextFinderです。アプリケーションをデバッグし、最初に JBehave を開始した「メイン スレッド」と、ストーリー ファイルを実行するためにエグゼキューター サービスから起動された「ストーリー スレッド」の両方のスレッドを一時停止すると、クラスローダーのインスタンスが同じであることがわかります。また、両親などのインスタンス。

しかし、への呼び出し

Thread.currentThread().getContextClassLoader().getResource("HelloWorld.story")

メイン スレッドでは完全に機能し、ストーリー スレッドでは失敗して null を返します。

ContextFinder のソース コードから判断すると、スタック上のクラスのすべての ClassLoader を収集する以外にはほとんど何もしていないようです。だから私はこれを試しました:

SomeClass.class.getClass().getClassLoader().getResource("HelloWorld.story")

...同じ結果です。

これは私には奇妙すぎる。この動作が表示される理由をデバッグまたは解放するためのポインタをいただければ幸いです。

4

1 に答える 1

2

OSGi では、スレッド コンテキスト クラスローダー (TCCL) は基本的に定義されていません。使用は避けるべきです。

標準 OSGi の拡張機能として、Equinox は ContextFinder と呼ばれるものを提供します。これは、スタック インスペクションを実行して、コール スタック内の最上位の OSGi バンドル クラスローダーを見つけようとします。ただし、ほとんど制御できず、結果がまったく予期しないものになる可能性があります。もちろん、これは Equinox 固有の拡張であるため、ContextFinder が適切に機能することに依存するコードは、他のすべての OSGi フレームワークでは失敗します。

したがって、これをデバッグしようとして時間を無駄にするよりも、TCCL をまったく使用しない方がよいでしょう。特定のクラスに関連するリソースをロードする場合は、リテラル クラス オブジェクトから実行します。たとえば、次のようになります。

MyClass.class.getResource("HelloWorld.story");

更新

私はあなたの最初の質問でこれに気づきました: SomeClass.class.getClass(). この結果は、java.lang.Classそれ自体のクラス オブジェクトになります。これを呼び出すgetClassLoader()と、常にJVM ブート クラス ローダーが返されます。おそらく意図したものではありません。

于 2013-04-15T18:51:48.307 に答える