Javaクラスローダー

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

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

1. クラスロードのプロセス
--------------

各Javaクラスは、クラスローダーによってロードされなければならない。さらに、Javaプログラムは外部ライブラリを利用する可能性もあり、また、それ自身が複数のライブラリで構成されている場合もある。

JVMが開始されると、date=2019年1月:

ブートストラップクラスローダー 
拡張クラスローダー 
システムクラスローダー ブートストラップクラスローダーは、中核のJavaライブラリを /lib ディレクトリからロードする//core.jar//、//server.jar//、//rt.jar//などのJARファイルに格納されている。}}。このクラスローダーはJavaVMの中心部分であり、ネイティブコードで記述されている。

拡張クラスローダーは、拡張ディレクトリ  にあるコードをロードする。これは、sun.misc.Launcher$ExtClassLoader クラスで実装されている。

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

2. ユーザー定義のクラスローダー
-----------------

既定では、ユーザーのクラスは全てシステムクラスローダーからロードされるが、ユーザーが定義した java/lang に置き換えたり、さらにクラスローダーの連結構造をユーザー定義したり、といったこともできる。

これにより、たとえば以下のようなことが可能になる:

クラスのロード・アンロードを実行時に行う。たとえば、実行時にHTTPリソースからライブラリを動的にロードするなど。これは以下の用途において重要な機能である:
スクリプト言語の実装。たとえばJythonやGroovyなど。
JavaBeansビルダーの利用。
ユーザー定義の拡張性  を可能にする。
複数の名前空間の間でのやりとりを可能にする。これは、CORBA / RMIの基礎となっている。
Javaバイトコードがロードされる方法を変える 。
ロード済みのバイトコードを改変する 。

3. Jakarta EEにおけるクラスローダー
------------------------

Jakarta EE  のアプリケーションサーバーは、通例サーバーに配置されたWARやEARアーカイブを階層的に配置されたクラスローダーでロードして、アプリケーション同士を隔離している。 いわゆる"サーブレットコンテナ"は、通例複数のクラスローダーを用いて実装されている。

4. JAR地獄
--------

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

JAR地獄の発生する状況としては次の3つがある。

一つ目は、Javaアプリケーションの開発や配置の際に、たまたま同じライブラリの2つのバージョンが同時に利用可能になってしまった場合である。この場合、処理系はエラーを発生させず、単純にどちらか一方のライブラリからのみクラスをロードする。使用するライブラリのリストに新しいライブラリを追加した場合、アプリケーションは古いライブラリを使っているのと同じ振る舞いになるものと考えられる。
問題が発生するもう一つの状況は、2つのライブラリAとBが、別のライブラリCの異なるバージョンをそれぞれ要求している場合である。 ライブラリCの各バージョンでクラス名が変わらないなら、ライブラリCの各バージョンを一つのクラスローダーで同時にロードする方法は存在しない。
JAR地獄で最も複雑な問題は、クラスローダーの複雑性によって発生する。Javaプログラムでは単一の「フラットな」クラスローダーだけでなく、ネストした、協調して動作する複数のクラスローダーを使用できる。別々のクラスローダーによってロードされたクラスは複雑に相互作用するが、開発者がその機序を十分に理解していない場合、不可解なエラーやバグが発生する。OSGiアライアンスは、現在および将来において、広く利用されているJava ME、Java SE、Jakarta EEの各VMでJAR地獄を解決するべく、モジュール方式のフレームワークを策定している。これは、マニフェストファイル中に書かれたメタデータを使い、JARファイルをパッケージ単位で操作するものである。バンドルはパッケージをエクスポートしたりインポートしたり、パッケージをプライベートに保っておいたりすることができ、これにより基本的なモジュール化と、バージョン付けされた依存関係管理が行える。

JAR地獄に対する改善策として、2005年にJava Community ProcessによるJSR 277の策定が始まり、その結果として「Java Module System」が定義された。これは、配布フォーマット、モジュールのバージョン体系、共通モジュールのリポジトリをJavaに導入することを目的としていたが、バージョニングの問題などで論争が起き、2008年12月、SunはJSR 277を保留とすることを発表した。その後、後継となるJSR 376のJavaプラットフォームモジュールシステムとしてJava 9で正式に導入された。

5. 脚注
-----

5.1. 注釈
-------

5.2. 出典
-------

6. 関連項目
-------

JAR 
ローダ
DLL地獄
OSGi
Apache Maven

7. 外部リンク
--------

Article "[1]" by Brandon E. Taylor
Article "[2]" by Jeff Hanson
Article "[3]" by Andreas Schaefer
Article "[4]" by Sheng Liang and Gilad Bracha
Article "[5]" by Jeremy Whitlock
Article "[6]" by Dr. Christoph G. Jung in //Java Specialist Newsletter//
Article "[7]" by Don Schwarz
[8] - now at [9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]
[17] — A Java profiler that includes a class loading log view and graph