技術の話をするところ2010-07-03クラスローダについてJavaJavaでは欠かせないクラスをロードするためのクラスローダ。普段意識していないかもしれませんが、しっかりと縁の下で支えているよね。通常、クラスは必要になったとき初めてロードされる。Javaの実行系は、クラスローダーがあるおかげでファイルやファイルシステムについて知る必要がない。大きく分けて以下の3つの種類があります。クラスローダブートストラップは、Javaのコアライブラリ($JAVA_HOME/lib/rt.jar)のライブラリ、パッケージがjavaから始まるクラス群をロードするクラスローダ。通常、自作したクラスは自分でクラスパスを指定しないと実行させることができない。ブートストラップだけはクラスパスは指定しないで利用できる。エクステンションは、$JAVA_HOME/lib/extやjava.ext.dirsで指定されたパスにあるクラスをロードするためのクラスローダ。システムクラスローダは、クラスパス変数で指定したクラスをロードするクラスローダだ。これらには親子関係がある。ブートストラップ←エクステンション←システムという関係らしい。これはクラスのロードの順番に影響するということ。子クラスローダでクラスをロードする場合は、まず親のクラスローダに処理を委譲する。そこで検索できなかった場合に、子のクラスローダで処理する。アプリケーションサーバのクラスローダさて、アプリケーションサーバではどうなっているか。Tomcatでは以下のような感じ。HOW-TOBootstrapSystemCommonWebAppの階層になっています。Commonは$CATALINA_HOME/libのjarが読み込まれるクラスローダ。WebAppはウェブアプリケーション単位で作られるクラスローダだ。注意が必要なのは、以下のようにクラスの検索順を意識しておく必要があるってことだ。$CATALINA_HOME/libのクラスを自分のアプリケーション内のクラスを優先的に検索させることも可能。これを意識してないとドハマリするときあるので注意。application$CATALINA_HOME/lib$CATALINA_HOME/lib/*.jarウェブアプリ(war)はTomcatのプラグイン的存在。アプリケーションサーバのOSGi化は自然な流れ。そもそもなんでこんな複雑なん?って話ですが、ヒントはここに。Javaはクラスローダと呼ばれるそれほど賞賛されてはいない機能を持っていて、それによって、実行時のパスをさらに細分化することができる。一般には、全てのクラスはシステムクラスローダによってロードされる。実行時の空間を異なる複数のクラスローダに分けているシステムもある。良い例はTomcat(や他のサーブレットエンジン)であり、多くの場合一つのウェブアプリケーションに一つのクラスローダを持っている。これによって、ウェブアプリが普通に機能しながら、同じJVM助運の他のウェブアプリに寄って定義されたクラスを(偶然だろうとそれ以外の理由であろうと)見ることができないようになっている。これが機能するための方法は各ウェブアプリが独自のクラスローダでクラスをロードすることであり、(局所的な)ウェブアプリの実装は他のウェブアプリの実装と衝突するようなクラスをロードしないことである。このことが要求することは、どんなクラスローダチェーンに対してもクラススペースが一貫しているということだ。これは、一度に2つのクラスローダからロードされた2つのUtil.classを保持することが、もしそのクラスローダが互いに不可視であるならば、可能であるという意味である。(それはまた、サーブレットエンジンが再起動することなく変更を際デプロイすることができるようにしているものでもある。これはサーブレットエンジンが新しいクラスローダを作成して、実行時に新しいバージョンのクラスを再ロードすることを可能にしている。)ここでわかることは、WebApp1とWebApp2でUtil.classがそれぞれにロードされていても(WEB-INF/libに配置したjarにUtil.classが存在するような状況)、お互いにクラスローダが見えないなら、仮にバージョンが異なってもクラスローディングに競合が起きにくいようになっているということです。昨今ではひとつのウェブアプリケーションでも複雑な要件を実現することも少なくないので、ウェブアプリケーション単位から、さらに役割ごとにクラスローディングの空間を分けて管理したほうがよいのではと思うことが多い。プラグイン指向なシステムでは上記のような問題がアプリケーション単体で起こり得る。同一アプリ上に同じLog4Jでもバージョンが異なるjarをローディングしたいという状況はよくある。いう場合でも、OSGiフレームワークを使うとクラスロードの整合性を維持できるため簡単に実現できる。http://www.eclipse.org/proposals/virgo/はTomcatをベースにOSGiに対応したアプリケーションサーバ。SpringSourceが開発していたものをEclipseプロジェクトに寄贈したプロジェクト*1。上述した考えをアプリケーションサーバに適用したモデルだ。Virgoを使いたいですが、既存案件でTomcat上にOSGiランタイムを設定して起動をかけるのは非常に面倒です。Licenceで実装中です。完成していて、OSGiに対応していないサーブレットコンテナ上にOSGiアプリケーションを構築できるようになります。Frameworkに登録すると動的にサーブレットの追加もできます。WicketもOSGiの助けを借りてバンドル(プラグイン)ベースのアプリケーションが実装できるようになります。APIで動的なプロビジョニングを可能にする予定。ちなみにプロジェクト名は獅子王(sisioh)プロジェクトです。(ウェブサイトがへぼいのでURL貼れないのですが、、、)やることが多すぎなんで、気合入れていきたいと思います。*1:といっても、コミッタはSpringSourceの方が多いです。Sourcingを学ぶための教材ServiceとDCIについて月別アーカイブはてなブログをはじめよう!j5ik2oさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。