- - PR -
自作ClassLoader
1
投稿者 | 投稿内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-06-30 11:28
こんにちは。今度は、自作ClassLoaderではまっています。
自分で作っているアプリケーションサーバーに、ホットデプロイ形式でJarを読み込めるフォルダーがあって、そこからホットデプロイで読み込む為のクラスローダを作っていてはまっています。 次のことで、詳しい方いらっしゃったら教えてください。 ・ClassLoaderがクラスをLoadするときのメカニズム ・InnerClassをどのように扱っているか ・Classloaderとしては「.property」ファイルをどのように処理しているか、処理する必要があるのか ・どのようなときにjava.lang.LinkageError: duplicate class definition:が出てしまうか が分かりません。 自分でも調べているのですが、もし、詳しい方がいらっしゃったら御教示ください。 よろしくおねがいします。 _________________ Alinous-Core SQL-HTML Language commiter Tomohiro Iizuka http://jp.alinous.org https://sourceforge.jp/projects/alinous-core/ | ||||||||||||||||
|
投稿日時: 2007-06-30 11:48
自己レスですみません。
今、ClassLoaderをいろいろと調べています。 今までは、全部、Jarに存在するクラスが名前解決可能だったのですが、今回はそうではありません。使われていないクラスがあって、そのクラスが他のメンバーへの参照を持っていたりして、そこで、メソッドのメンバーにJARに含まれていないClassが使われていてもOKです。 なので、Reflectionでクラスを総スキャンする必要があるときには、そこで起きるNoClassDefExceptionを一部無視する必要があったりします。 また、クラスを読み込むときに、findClaass()が使われるケースとloadClass()が使われる2パターンがあるようです。 java.lang.LinkageError: duplicate class definition:はそのへんのメカニズムとどうやら、関係しているようです。 もうちょっと、また、調べてみます。 | ||||||||||||||||
|
投稿日時: 2007-06-30 12:11
ClassLoaderとURLClassLoaderのソースを眺めてみましょう。 loadClass() ⇒ findClass() ⇒ defineClass() よくある方法では、URLClassLoaderを拡張して、 ・ロード時の挙動を変えたい(子⇒親の優先度ポリシーなど)のならloadClass() ・クラスファイルの解決(読み込み)方法を拡張したいならfindClass() これらをそれぞれ必要に応じてオーバーライドします。 単にクラスローダの構築後にjarをクラスパスに追加したいだけならば、 URLClassLoaderを拡張してaddURL(URL)をpublicにするだけでも可能です。
「外側クラス名$内側クラス名」という普通の名前になるので特に考慮は不要です。
findResource()とfindResources()のオーバーライドが必要です。 優先度ポリシーを変える場合はgetResource()系もオーバーライドしましょう。
LinkageErrorはクラスローダというよりはロードしたクラス側の問題かと。 「duplicate class definition」は出たことないので知りませんが、 同じクラスを同じクラスローダで複数回defineClass()した場合では? | ||||||||||||||||
|
投稿日時: 2007-06-30 12:19
Java仮想マシン仕様がこのあたり詳しいですよ。
一度読んでみることをお勧めします。 ClassLoaderを自作する場合、loadClass()をオーバーライドすることになります。 loadClass()は戻り値がClassなわけですが、どうやってClassオブジェクトを生成するかというとdefineClass()を利用して生成します。 つまり、jarなどのアーカイブされた状態からClassをあらわすバイナリを取得し、そのバイナリをdefineClass()に渡してClassを得るという流れです。 loadClass()のソースコードは以下のようになっています。(JDK1.6 java.lang.ClassLoaderより)
・findLoadedClass()の実装により読み込み済みClassの場合はキャッシュを使う ・親があれば親のloadClass()で読み込みを試みる ・親がなければfindClass()で探す "duplicate class definition"のエラーメッセージからするとfindLoadedClass()の実装に問題があったりするのでしょうか? 多重に読み込むとリンクの際にエラーとなるのではないでしょうか。 「.property」ファイルなどは、つまるところクラスパス上に配置して getResourceAsStream()で読み込むことが多いので、その点を実装してあれば大丈夫では? getResourceAsStream()の実装を作り、その実装を利用してclassのバイナリを読み込んでdefineClass()するのが通常でしょうね。 InnerClassは独自の命名規約で変換されるはず。ちょっと資料が見つからないのですが 完全修飾名は外部クラス名$内部クラス名になります。 無名クラスの場合は外部クラス名$0といったような数字になります。 このあたりは探せばちゃんとした仕様がみつかるはず。 | ||||||||||||||||
|
投稿日時: 2007-06-30 12:28
あしゅさん、nagiseさん
ありがとうございます。 おかげさまで解決しそうです。 リソース系のシステムプロパティもClassLoaderで扱っているとは、今回、正直、初めて知りました。 どうも、自分自身がこのClassLoaderで、Jarに入っているクラスのフルスキャンをかけていた関係で、その中でJarに含まれていないクラスがMethodの引数にあって例外が発生していて、その例外が別の例外にキャッチされてcauseになって、他の例外に変換されていた関係ではまっていたようです。 java.lang.LinkageError: duplicate class definitionは、やはり、2回同じクラスをdefineClass()したときに出ていました。ホットデプロイを実現するには、ClassLoaderを読み込むJar用に小分けして、Jarファイルに変更があったら子ClassLoaderごと捨てるのが良さげです。 (ClassLoaderにはUnloadするメソッドがなかったので) これで、きちんとしたClassLoaderが出来そうです。 本当にありがとうございます。 |
1