クラスローダー!クラスが読まれる仕組み

Eclipseで作成したJava(class)をコマンドプロンプトで実行する」で、実行に必要なクラスファイルが 何処にあるかがわかるように、クラスパスを指定する必要がありました。

それでは、どのようにクラスがロードされているかを確認していきます。これにより、 クラスパスに関する理解を深めていきたいと思います。

参考1:「Java Magazine 第24号[2016年1月発行]

参考2:「How ClassLoader Works in Java

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アプリケーションは独自のクラスローダーを使用し、委譲の仕組みを 少し曲げています。この仕組みによりバージョンの異なる同じライブラリーが使えるよう 工夫されています。

これは、アプリケーションクラスローダー(独自の)が先にクラスをロードし 委譲を後に回してアプリケーションで用意されたクラスを先にロードすることになります。 また、一意性の原則からロードされたクラスが再度ロードされる事は無いため、バージョンの異なる同じライブラリー が共存できることになります。