目次 | 前へ | 次へ

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 では、AppletClassLoader は 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 © 1997-1999 Sun Microsystems, Inc. All Rights Reserved.

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