クラスローダー!クラスが読まれる仕組み
「Eclipseで作成したJava(class)をコマンドプロンプトで実行する」で、実行に必要なクラスファイルが 何処にあるかがわかるように、クラスパスを指定する必要がありました。
それでは、どのようにクラスがロードされているかを確認していきます。これにより、 クラスパスに関する理解を深めていきたいと思います。
3つのクラスローダー
JVMのクラスローダーは、基本的に3つ存在します。Bootstrap,Extension,Systemクラスローダーの3つです。
3つのクラスローダーは、階層構造になっており次のような関係を持っています。
それぞれのクラスローダーは、定義済みのロケーションを持っており、そこからクラスファイルを ロードします。
Bootstrapクラスローダーでは、rt.jar(JDKやJREのインストール先にあるJava標準クラス)からクラスをロードします。 また、Extensionクラスローダーでは、jre/lib/extディレクトリもしくはjava.ext.dirsシステムプロパティが示す他のディレクトリからクラスをロードします。 Systemクラスローダーは、CLASSPATH環境変数,-classpathもしくは-cpコマンドライン引数,JAR内の マニフェストファイルにあるClass-Path属性から、アプリケーション固有のクラスをロードします。
この3つのクラスローダーには、親子関係があり図のようにBootstrapクラスローダーがすべてのクラスローダーの親となります。
クラスローダーの関係と動作
クラスローダーは、3つの基本原則に基づいて動作しています。
委譲(Delegaion)
子クラスローダーにクラスロードの依頼があると、親クラスローダーにクラスロードの依頼を委譲(Delegaion)します。
クラスが見つからない(又はロードできない)場合、子クラスローダーがクラスのロードを行います。
例えば、hoge.classというクラスがあるとして、このクラスが初めてロードされる場合、 Systemクラスローダーが親のExtensionクラスローダーへロードを委譲し、次にBootstrapクラスローダーへ委譲されます。
Bootstrapクラスローダーは、rt.jarからhoge.classを検索し、発見できないのでExtensionクラスローダーへ 引き継がれます。Extensionクラスローダーは、jre/lib/extディレクトリを検索し、発見できない場合 Systemクラスローダーへ引き継ぎます。Systemクラスローダーは、指定されたクラスパスからクラスをロードします。
それぞれのクラスローダーは、クラスが見つかった時点でそのクラスをロードし、子のクラスローダーはロードしません。
可視性(Visibility)
各クラスローダーの関係として、子クラスローダーは親クラスローダーがロードしたクラスを 参照することができますが、親が子を参照することはできません。
一意性(Uniqueness)
最後の原則は、親がロードしたクラスを子がロードすべきではなく、一意性を保つべき というものがあります。
例外!!Webアプリケーションは少し違っている
「原則」という事ですので、特別な場合もあるようです。
Webアプリケーションの場合、1つのアプリケーションサーバーに複数のアプリケーションを 同時に配置(デプロイ)することができる為、デプロイされたそれぞれのアプリケーションが 自身のクラスと他のアプリケーションのクラスを区別できる仕組みが必要となります。
そのため、Webアプリケーションは独自のクラスローダーを使用し、委譲の仕組みを 少し曲げています。この仕組みによりバージョンの異なる同じライブラリーが使えるよう 工夫されています。
これは、アプリケーションクラスローダー(独自の)が先にクラスをロードし 委譲を後に回してアプリケーションで用意されたクラスを先にロードすることになります。 また、一意性の原則からロードされたクラスが再度ロードされる事は無いため、バージョンの異なる同じライブラリー が共存できることになります。