Javaでクラスをロードします。 理論





Javaプラットフォームの主な機能の1つは、動的クラスロードモデルです。これにより、メインアプリケーションをリロードせずに実行可能コードをJREにロードできます。 この機能は、最近人気が高まっているアプリケーションサーバーで広く使用されています。



この記事では、動的コードロードモデルの基本概念、側面、および原理について説明します。 次の記事では、プラグインモジュールアーキテクチャを備えた主要なアプリケーションメカニズムとして、独自のクラスローダーの実装を検討します。





はじめに



ランタイムで使用されるクラス(環境内のjava.lang.Classクラスのインスタンスとファイルシステム内の.classファイル)は、何らかの方法でJavaのローダーによってロードされました。 クラスAをロードしたローダーを取得するには、A.class.getClassLoader()メソッドを使用する必要があります。



いくつかの例外を除き、クラスは必要に応じてロードされます。 rt.jar(特にjava.lang。*)の基本クラスは、アプリケーションの起動時にロードされます。 拡張クラス($ JAVA_HOME / lib / ext)、ユーザークラス、およびほとんどのシステムクラスは、使用時にロードされます。



ブートローダーの種類



Javaには3種類のローダーがあります。 これは、基本的なブートローダー(ブートストラップ)、システムローダー(システムクラスローダー)、拡張ローダー(拡張クラスローダー)です。



ブートストラップ -JVMレベルで実装され、ランタイムからのフィードバックはありません。 このローダーは、$ JAVA_HOME / libディレクトリからクラスをロードします。 つまり みんなのお気に入りのrt.jarは、基本的なブートローダーによってロードされます。 したがって、java。*クラスからローダーを取得しようとすると、常にnullで終了します。 これは、すべての基本クラスが基本ローダーでロードされ、管理環境からのアクセスではないためです。



-Xbootclasspathスイッチを使用して基本クラスのロードを制御できます。これにより、基本クラスのセットをオーバーライドできます。



システムクラスローダーは、JREレベルで既に実装されているシステムローダーです。 Sunでは、JREはクラスsun.misc.Launcher $ AppClassLoaderです。 このローダーは、CLASSPATH環境変数でパスが指定されているクラスをロードします。



-classpathスイッチまたはjava.class.pathシステムオプションを使用して、システムクラスのロードを制御できます。



拡張クラスローダー-拡張ローダー。 このローダーは、$ JAVA_HOME / lib / extディレクトリからクラスをロードします。 Sunでは、JREはクラスsun.misc.Launcher $ ExtClassLoaderです。



拡張機能のダウンロードは、java.ext.dirsシステムオプションを使用して制御できます。



コンセプト



現在のローダー(Current Classloader)とコンテキストローダー(Context Classloader)を区別します。



Current Classloaderは、コードが現在実行されているクラスローダーです。 現在のローダーは、デフォルトで実行時にクラスをロードするために使用されます。 特に、Class.forName( "")/ ClassLoader.loadClass( "")メソッドまたは以前にロードされていないクラス宣言を使用します。



Context Classloader-現在のスレッドのコンテキストローダー。 Thread.getContextClassLoader()/ Thread.setContextClassLoader()メソッドを使用して、このブートローダーを取得してインストールできます。 コンテキストローダーは、新しいスレッドごとに自動的にインストールされます。 この場合、親スレッドのローダーが使用されます。



委任モデルをダウンロード



Java 2 Platform、Standard Edition、v1.2以降、クラスローダーは階層を形成します。 ルートはベースです(彼には祖先はありません)。 他のすべてのブートローダーは、初期化時に、親ブートローダーへのリンクをインスタンス化します。 このような階層は、負荷委任モデルに必要です。 一般に、階層は次のとおりです。







クラスの読み込み権は、階層の最下位のローダーから最上位のローダーに再帰的に委任されます。 このアプローチにより、可能な限りベースに近いローダーでクラスをロードできます。 これにより、クラスの最大範囲が実現されます。 スコープとは、以下を指します。 各ローダーは、ロードしたクラスを追跡します。 これらのクラスの多くはスコープと呼ばれます。







ダウンロードプロセスを詳細に検討してください。 ユーザークラスStudent変数の宣言が実行システムで満たされるようにします。



1)ブートローダーは、キャッシュでStudentクラスを検索しようとします。

_1.1)クラスが見つかると、ロードが完了します。

_1.2)クラスが見つからない場合、ダウンロードは拡張ローダーに委任されます。

2)拡張ローダーは、キャッシュでStudentクラスを検索しようとします。

_2.1)クラスが見つかると、ロードが完了します。

_2.2)クラスが見つからない場合、ダウンロードはベースローダーに委任されます。

3)ベースローダーは、キャッシュでStudentクラスを検索しようとします。

_3.1)クラスが見つかると、ロードが完了します。

_3.2)クラスが見つからない場合、ベースローダーはそれをロードしようとします。

__3.2.1)ダウンロードが成功した場合、完了します;)

__3.2.2)それ以外の場合、制御は拡張ローダーに転送されます。

_3.3)拡張ローダーがクラスをロードしようとしています。

__3.3.1)ダウンロードが成功した場合、完了します;)

__3.3.2)それ以外の場合、制御はシステムブートローダーに転送されます。

_3.4)システムローダーがクラスをロードしようとしています。

__3.4.1)ダウンロードが成功した場合、完了します;)

__3.4.2)それ以外の場合、java.lang.ClassNotFoundExceptionがスローされます。



ユーザーローダーがシステムに存在する場合、ユーザーローダーは

a)クラスjava.lang.ClassLoaderを拡張します。

b)動的ローディングモデルをサポートします。



内側



-verbose:classスイッチを使用して最も単純なアプリケーションを実行します。



public class A { }



public class B extends A { }



public class C extends B { }



public class Main {



public static void main( String args[]) {

C c = new C();

B b = new B();

A a = new A();

}

}



* This source code was highlighted with Source Code Highlighter .








出力は、クラスが誤った順序でロードされたことを示しています。 これは継承によるものです。



[ファイルからメインをロード:/ C:/ devel / CL / bin /]

[ファイルからAをロード:/ C:/ devel / CL / bin /]

[ファイルからBをロード:/ C:/ devel / CL / bin /]

[ファイルからCをロード:/ C:/ devel / CL / bin /]



おわりに



次の記事はより興味深いものになります;)



All Articles