Javaクラスローダー

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

Javaクラスローダー: Java Classloader)とは、Java仮想マシンの一部で、JavaクラスJava仮想マシンに動的にロードする役割を持つ [1]。通常、クラスは必要になったとき初めてロードされる。Javaの実行系は、クラスローダーがあるおかげでファイルやファイルシステムについて知る必要がない。クラスローダについて学習する場合には、この委譲が重要な考え方である。

ソフトウェアのライブラリとは、オブジェクトコードと多かれ少なかれ関連しているが、Java 言語ではライブラリはJarファイルに格納され、様々なオブジェクトを格納することができる。クラスはコードに名前をつけた一つの単位であり、クラスローダはライブラリを見つけて内容をロードし、ライブラリに含まれるクラスをロードする責務を持つ。クラスのロードは「必要に応じて」であり、すなわちクラスがプログラムに実際に必要になるまで行われない。指定された名称のクラスは、あるクラスローダーにたった一度だけしかロードされない。

クラスロードのプロセス[編集]

各Javaクラスは、クラスローダーによってロードされなければならない[2]。さらに、Javaプログラムは外部ライブラリ(つまり、プログラムの作者とは別の誰かが開発し提供するライブラリ)を利用する可能性もあり、また、それ自身が複数のライブラリで構成されている場合もある。

JVMが開始されると、3つのクラスローダーが使用される[3] [4]:

  1. ブートストラップクラスローダー
  2. 拡張クラスローダー
  3. システムクラスローダー

ブートストラップクラスローダーは、中核のJavaライブラリをロードする。[5] (<JAVA_HOME>/lib ディレクトリ)。このクラスローダーはJavaVMの中心部分であり、ネイティブコードで記述されている。

拡張クラスローダーは、拡張ディレクトリ(<JAVA_HOME>/lib/ext や、java.ext.dirsプロパティで指定された他のディレクトリ)にあるコードをロードする。これは、sun.misc.Launcher$ExtClassLoader クラスで実装されている。

システムクラスローダーは、java.class.path 、すなわちシステムCLASSPATH 変数にあるクラスをロードする。こちらは、sun.misc.Launcher$AppClassLoader クラスで実装されている。


ユーザー定義のクラスローダー[編集]

規定では、ユーザーのクラスは全てシステムクラスローダーからロードされるが、ユーザーが定義したClassLoader' に置き換えたり、さらにクラスローダの連結構造もユーザー定義することができる。

これにより、下例のようなことが可能になる:

  • クラスのロード・アンロードを動的に(たとえば、HTTPから)行う。
  • この用途は、
    • スクリプト言語の実装
    • ビーンビルダを用いて、
    • ユーザーが拡張の仕組みを定義する
    • 複数の名前空間が交わることを可能にする。これは、CORBA / RMIの基礎となっている。
  • バイトコードがロードされる方法を変える(たとえば、暗号化されたJavaクラスをロードする[6])。
  • ロード済みのバイトコードを改変する(たとえば、アスペクト指向プログラミングで用いれば、ロード時の織り込み)。

Java Enterprise Editionにおけるクラスローダー[編集]

Java Platform, Enterprise Edition(JEE)のアプリケーションサーバーは、通例サーバーに配置されたWAREARアーカイブを階層的に配置されたクラスローダーでロードして、アプリケーション同士を隔離している。 いわゆる"サーブレットコンテナ"は、通例複数のクラスローダーを用いて実装されている。[2][7]

JAR地獄[編集]

DLL地獄に似た言葉としてJAR地獄という言葉があるが、これはクラスのロードが思ったとおりに行われない状況全般を指して使われる[8]。 JAR地獄の発生する状況としては次の3つがある。

  • 一つ目は、Javaアプリケーションの開発や配置の際に、たまたま同じライブラリの2つのバージョンが同時に利用可能になってしまった場合である。この場合、処理系はエラーを発生させず、単純にどちらか一方のライブラリからのみクラスをロードする。使用するライブラリのリストに新しいライブラリを追加(置き換えではなく)した場合、アプリケーションは古いライブラリを使っているのと同じ振る舞いになるものと考えられる。
  • 問題が発生するもう一つの状況は、2つのライブラリAとB(または、アプリケーションAとそれが使っているライブラリB)が、別のライブラリCの異なるバージョンをそれぞれ要求している場合である。 ライブラリCの各バージョンでクラス名が変わらないなら、ライブラリCの各バージョンを一つのクラスローダで同時にロードする方法は存在しない。
  • JAR地獄で最も複雑な問題は、クラスローダーの複雑性によって発生する。Javaプログラムでは単一の「フラットな」クラスローダーだけでなく、ネストした、協調して動作する複数の(場合によっては非常に多くの)クラスローダーを使用できる。別々のクラスローダーによってロードされたクラスは複雑に相互作用するが、開発者がその機序を十分に理解していない場合、不可解なエラーやバグが発生する[9]

OSGiアライアンスは、現在および将来において、広く利用されているJavaME, SE, EEの各VMでJAR地獄を解決するべく、モジュール方式のフレームワークを策定している(1998年のJSR 8から始まっている)。これは、JAR manifest中に書かれたメタデータを使い、JARファイル(バンドルと呼ばれる)をパッケージ単位で操作するものである。バンドルはパッケージをエクスポートしたりインポートしたり、パッケージをプライベートに保っておいたりすることができ、これにより基本的なモジュール化と、バージョン付けされた依存関係管理が行える。

JAR地獄に対する改善策として、2005年にJava Community ProcessによるJSR 277の策定が始まり、その結果としてJava Module Systemが定義された。これは、配布フォーマット、モジュールのバージョン体系、共通モジュールのリポジトリ(目的は.NET FrameworkGlobal Assembly Cacheに類似)をJavaに導入することを目的としていたが、2008年12月、SunはJSR 277を保留とすることを発表した[10]

関連項目[編集]

参考文献[編集]

  1. ^ Binildas, Mcmanis (1996年1月10日). “The basics of Java class loaders”. JavaWorld. 2008年1月26日閲覧。
  2. ^ a b Binildas, Christudas (2005年1月26日). “Internals of Java Class Loading”. onjava.com. 2009年10月2日閲覧。
  3. ^ Understanding Extension Class Loading”. java.sun.com (2008年2月14日). 2008年1月26日閲覧。
  4. ^ Dennis, Sosnoski (2003年4月29日). “Classes and class loading”. ibm.com. 2008年1月26日閲覧。
  5. ^ core.jarserver.jarrt.jarなどのJarファイルに格納されている
  6. ^ Vladimir, Roubtsov (2003年9月5日). “Cracking Java byte-code encryption”. javaworld.com. 2008年1月26日閲覧。
  7. ^ Tim, deBoer (2002年8月21日). “J2EE Class Loading Demystified”. ibm.com. 2008年1月26日閲覧。
  8. ^ http://incubator.apache.org/depot/version/jar-hell.html
  9. ^ http://www.ibm.com/developerworks/jp/websphere/library/java/j2ee_classloader/2.html#N10118
  10. ^ http://www.osgi.org/News/20081217

外部リンク[編集]