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 /]
おわりに
次の記事はより興味深いものになります;)