目次||

5 安全なクラス・ローディング

動的クラス・ローディングはJava仮想マシンの重要な機能で、Javaプラットフォームでソフトウェア・コンポーネントを実行時にインストールできるようにします。この機能には、独特の特長がいくつかあります。まず、遅延ローディングは、要求があってもできるかぎり直前までクラスがロードされないことを意味します。また、動的クラス・ローディングは、リンクタイム・チェックを追加することによって、Java仮想マシンの型の安全性を維持します。リンクタイム・チェックは、特定のランタイム・チェックと置き換わるもので、1回のみ実行されます。さらに、プログラマは、特定のクラスのロード元となるリモートの場所を指定したり、クラスに適切なセキュリティ属性を割り当てたりするような、独自のクラス・ローダーを定義できます。また、クラス・ローダーを使用して、様々なソフトウェア・コンポーネントに個別の名前空間を提供できます。たとえば、ブラウザは、異なるWebページのアプレットを別々のクラス・ローダーを使用してロードできるため、これらのアプレット・クラス間である程度の分離が維持されます。実際、これらのアプレットに同じ名前のクラスが含まれていてもかまいません。これらのクラスは、Java仮想マシンによって異なる種類として扱われます。

クラス・ローディングのメカニズムは、Javaプログラミング言語の動的性質の中心となっているだけではありません。クラス・ファイルの検索と取得、セキュリティ・ポリシーの参照、および適切なアクセス権を持たせたクラス・オブジェクトの定義は、クラス・ローダーが行うため、このメカニズムは、セキュリティの提供にも中心的な役割を果たしています。


5.1 クラス・ローダーのクラス階層

1つのJava仮想マシンに、クラス・ローダー・オブジェクトの複数のインスタンスが存在する可能性があるため、クラスをロードするときに、使用するクラス・ローダーをどのように決定するかは重要な問題です。Java 2 SDKでは、異なる属性を持った複数のクラス・ローダーのクラスが導入されたため、どの種類のクラス・ローダーを使用するのかも大きな問題です。

クラス・ローダーのクラス階層のルートは、java.lang.ClassLoaderという抽象クラスで、JDK 1.0で定義されて以来拡張されてきました。Java 2 SDK v 1.2で導入されたjava.security.SecureClassLoaderクラスは、抽象ClassLoaderクラスのサブクラスおよび固定実装です。java.net.URLClassLoaderクラスは、SecureClassLoaderのサブクラスです。

Appletviewerというユーティリティ・プログラムは、privateクラスであるsun.applet.AppletClassLoaderを使ってアプレットをロードします。JDK 1.0では、AppletClassLoaderはClassLoaderのサブクラスおよび固定実装です。Java 2 SDKでは、URLClassLoaderのサブクラスです。

クラス・ローダーのカスタム・クラスを作成する場合は、そのカスタム・クラス・ローダー特有の必要に応じて、上記の任意のクラス・ローダー・クラスのサブクラスにすることも可能です。AppletClassLoaderは、sun.* package内で定義されたprivateクラスで、サポートされておらず変更される可能性もあるので、AppletClassLoaderのサブクラス化は行わないでください。


5.2 初期クラス・ローダー

各クラスは、そのクラス・ローダーによってロードされ、各クラス・ローダー自体もクラスで、別のクラス・ローダーによってロードされる必要があるため、最初のクラス・ローダーはどこからロードされるのかという明らかな「鶏と卵の問題」の問題が起こるように見えます。クラスのローディング・プロセスをブートストラップする「初期」クラス・ローダーがあります。初期クラス・ローダーは、一般的にはCなどのネイティブ言語で記述されており、Javaコンテキスト内には現れません。初期クラス・ローダーは、ローカルのファイル・システムからプラットフォームに依存した方法でクラスをロードする場合がよくあります。

クラスには、java.*パッケージ内で定義されたクラスのように、Java仮想マシンと実行システムが正しく機能するために不可欠なものがあります。そのようなクラスはよく、基底クラスと呼ばれます。歴史的な理由から、このようなすべてのクラスには、NULLのクラス・ローダーが存在します。おそらく、このNULLクラス・ローダーが、初期クラス・ローダーの存在を示す唯一のしるしです。実際、NULLクラス・ローダーを、単に初期クラス・ローダーとしてみなす方が簡単です。

1つのJavaアプリケーション環境にすべてのクラスがあれば、クラスのローディング関係を反映するクラス・ローディングのツリーを簡単に形成できます。クラス・ローダーでないクラスは、すべて葉ノードです。各クラスの親ノードはそのクラスのクラス・ローダーで、NULLクラス・ローダーはルート・クラスです。クラス・ローダーが自分の祖先のクラス・ローダーをロードするという循環はありえないため、この構造はツリー構造になります。


5.3 クラス・ローダーの委譲

クラス・ローダーにクラスのロードが要求されると、そのクラス・ローダー自体がクラスをロードする場合と、そのクラスが別のクラス・ローダーにロードを行うように要求する場合があります。つまり、1つ目のクラス・ローダーは、2つ目のクラス・ローダーに委譲することができます。委譲関係は、どのクラス・ローダーがほかのどのクラス・ローダーをロードするかには関係ないという点では仮想的です。しかしむしろ委譲関係は、クラス・ローダー・オブジェクトの作成時に、親子関係として形成されます。ただし、システム・クラス・ローダーは、すべてのクラス・ローダーの委譲ルートの原型です。委譲関係に循環がないように注意してください。循環があると、委譲プロセスが無限ループに入ることがあります。

5.4 クラスの解釈処理アルゴリズム

Java 2 SDK ClassLoaderメソッドのデフォルト実装では、クラスをロードする際、次の順序でクラスが検索されます。 最初のステップでは、クラス・ローダーのローカル・キャッシュ(または機能的にそれと同等な、グローバル・キャッシュなど)で、ロードされたクラスがターゲット・クラスと一致するかどうかを調べます。最後のステップでは、クラスの検索メカニズムをカスタマイズする方法が提供されています。このため、カスタム・クラス・ローダーで、このメソッドをオーバーライドして、クラスの検索方法を指定できます。たとえば、アプレットのクラス・ローダーでこのメソッドをオーバーライドして、アプレットのホストに戻ってクラス・ファイルを検索し、ネットワーク経由でそのクラス・ファイルをロードできます。

これらのステップのどこかでクラスが検索されると、それが返されます。上のステップを使ってクラスが見つからない場合は、ClassNotFound例外がスローされます。

型の安全性のため、同じクラスが同じクラス・ローダーによって2回以上ロードされないように注意してください。クラスがすでにロードされたクラスでない場合、現在のクラス・ローダーは、タスクを親クラス・ローダーに委譲しようとします。このプロセスは、再帰的に実行されることもあります。このため、適切なクラス・ローダーが使われることが保証されます。たとえば、システム・クラスを検索する場合、システム・クラス・ローダーにたどり着くまで委譲プロセスが繰り返されます。

ここまで移譲アルゴリズムを見てきました。では、クラス名を指定されてそのクラスをロードするとき、どのクラス・ローダーから使い始めればよいでしょうか。クラス・ローダーを特定する規則は、次のとおりです。

URLClassLoaderのインスタンスおよびAppletClassLoaderのインスタンスの使用についての規則には例外があり、特定のシステム環境によっては、規則が変わる場合があります。たとえば、同じWebページから複数のアプレット・クラスをロードする場合、Webブラウザが既存のAppletClassLoaderを繰返し使用する場合もあります。

クラス・ローダーの能力のため、クラス・ローダー・インスタンスを作成できるプログラムを厳格に制限しています。一方、アプリケーションまたはアプレットに、URLの場所を指定し、それらからクラスをロードするための便利なメカニズムを与えることは望ましい方法です。どのプログラムでもURLClassLoaderクラスのインスタンスを作成できるようにするための静的メソッドを提供していますが、その他のタイプのクラス・ローダーについては提供していません。



目次||

Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.