1. 概要

Javaは、さまざまなタイプのクラスローダーを使用して、プログラムの実行中にリソースをロードします。 このチュートリアルでは、Javaの現在のローダーとスレッドクラスのローダーの動作の違いについて説明します。

2. クラスローダーは何をしますか?

Javaクラスローダーは、アプリケーションの実行に必要なクラスを見つけてロードします。 要求されたクラスが他のリソースに依存している場合、それらもロードされます。

必要なときにJavaプログラムによってさまざまなタイプのクラスをロードするために、適切なクラスローダーが必要です。

3. クラスローダー間の関係

Javaクラスローダーは階層関係に従います

クラスを検索またはロードする各要求は、それぞれの親クラスローダーに委任されます。 すべての祖先クラスローダーがクラスを見つけることができない場合、現在のクラスローダーはそれを見つけようとします。 ここで、「現在のクラス」とは、現在実行中のメソッドのクラスを意味します。

クラスローダー間のこの関係は、アプリケーション内のリソースの一意性を維持するのに役立ちます。さらに、クラスが親クラスローダーによってすでにロードされている場合、子クラスローダーはそれをリロードする必要はありません。

4. デフォルトのクラスローダー

クラスローダーは、それぞれのクラスパスに存在するクラスとリソースをロードします。

  • システムまたはアプリケーションクラスローダーは、アプリケーションクラスパスからクラスをロードします
  • 拡張クラスローダーは拡張クラスパスを検索します( JRE / lib / ext
  • BootstrapクラスローダーはBootstrapクラスパスを検索します( JRE / lib / rt.jar

BootstrapまたはPrimordialクラスローダーは、すべてのクラスローダーの親です。 Javaランタイム(JVM自体を実行するために必要なクラス)をロードします。

現在のクラスローダーは、線形の階層的な方法でリソースを検索します。 クラスローダーがクラスを見つけることができない場合、対応する子クラスローダーに java.lang.ClassNotFoundExceptionをスローします。 次に、子クラスローダーはクラスの検索を試みます。

階層内のどのクラスローダーのクラスパスにも必要なリソースが見つからないシナリオでは、最終結果として java.lang.ClassNotFoundExceptionに関連するエラーメッセージが表示されます。

デフォルトのクラス読み込み動作もカスタマイズできます。 クラスを動的にロードするときにクラスローダーを明示的に指定できます

ただし、異なるタイプのクラスローダーから同じクラスをロードする場合、これらはJVMによって異なるリソースと見なされることに注意してください。

5. コンテキストクラスローダー

デフォルトのクラスローダーとは別に、J2SEはコンテキストクラスローダーも導入しました。

Javaの各t heread には、コンテキストクラスローダーが関連付けられています。

スレッドクラスのgetContextClassLoader()および setContextClassLoader()メソッドを使用して、スレッドのコンテキストクラスローダーにアクセス/変更できます。

コンテキストクラスローダーは、スレッドの作成時に設定されます。 明示的に設定されていない場合、itはデフォルトで親スレッドのコンテキストクラスローダーになります。

コンテキストクラスローダーも階層モデルに従います。 この場合、ルートクラスローダーは、原始スレッドのコンテキストクラスローダーです。 原始スレッドは、オペレーティングシステムによって作成された最初のスレッドです。

アプリケーションの実行が開始されると、他のスレッドが作成される場合があります。 原始スレッドのコンテキストクラスローダーは、最初はアプリケーションをロードするクラスローダー、つまりシステムクラスローダーに設定されます。

階層のどのレベルでも、スレッドのコンテキストクラスローダーを更新しないと仮定します。 その結果、デフォルトでは、スレッドのコンテキストクラスローダーはシステムクラスローダーと同じであると言えます。 このようなシナリオでは、 Thread.currentThread()。getContextClassLoader()および getClass()。getClassLoader()操作を実行すると、どちらも同じオブジェクトを返します。

5.1. 委任に関する問題の処理

コンテキストクラスローダーは、必要なリソースがデフォルトのJavaクラスローダーのクラスパスに存在しない場合に重要です。 したがって、コンテキストクラスローダーを使用して、従来の線形委任モデルから分岐することができます。

クラスローダーの階層モデルでは、親クラスローダーによってロードされたリソースは子クラスローダーに表示されますが、その逆はありません。 一部のシナリオでは、親クラスローダーが子クラスローダーのクラスパスに存在するクラスにアクセスする必要がある場合があります。

コンテキストクラスローダーは、これを実現するための便利なツールです。 必要なリソースにアクセスするときに、コンテキストクラスローダーを目的の値に設定できます。 したがって、上記の場合、子スレッドのコンテキストクラスローダーを使用して、子クラスローダーレベルに存在するリソースを見つけることができます。

5.2. マルチモジュール環境

コンテキストクラスローダープロパティを設定している間、基本的にリソースをロードするためのコンテキストを切り替えています。 現在のクラスパスを検索する代わりに、別のクラスパスを指す新しいクラスローダーをフェッチします。 これは、サードパーティのモジュールからリソースをロードする場合、または異なるクラスの名前空間を持つ環境で作業している場合に特に役立ちます。

ただし、ここでは注意を払い、コンテキストクラスローダーのプロパティを元のクラスローダーにリセットして、将来の不一致を回避する必要があります。

6. 結論

この記事では、コンテキストクラスローダーを使用して、通常のクラスローダーではアクセスできないリソースをロードすることの重要性を分析しました。 必要なクラスをロードするために、特定のスレッドのコンテキストクラスローダーを一時的に更新することも選択できることがわかりました。

現在のメソッドが機能しているコンテキストを理解することが不可欠です。 同じ名前のリソースを異なるクラスパスに存在させることができます。 したがって、複数のクラスローダーからリソースをロードするときは、注意が必要です。