- - PR -
Tomcatでのダイナミックプロキシの使用について
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2005-03-14 14:48
ダイナミックプロキシとTomcatのクラスローダについて質問させていただきます。
環境 j2sdk1.4.6(win32) 開発 Eclipse3.0.1 APサーバ Tomcat5.0.28 ダイナミックプロキシクラス(java.lang.reflect.Proxyで生成したクラス)の インスタンスをセッションに格納して使用しているのですが、 リロード処理が行われる際にClassNotFoundExceptionが発生します。 ダイナミックプロキシを生成する為のインターフェイスが、 リロード処理のセッション復元時に見つからないという例外です。 これは、直列化されたオブジェクトを復元する際にクラスの解決を行いますが、 例外を見る限り、クラスの解決をStandardClassLoaderで行おうとしてしています。 Webアプリ側で作成したインスタンスですので、 本来ならWebappClassLoaderで解決しなければいけません。 実際に見つからないと言われているクラスをjarにして tomcatのcommon/libフォルダに配置すると、例外は発生しません。 (StandardClassLoaderから見える位置にクラスが存在すれば問題はない) 例外が発生する条件は、リロード処理が行われセッションの復元が行われる時ですが、 Webアプリの処理の中で直列化・復元を行う場合には一切問題ありません。 (プロキシクラスを解決するクラスローダがWebappClassLoaderであるため) また通常のクラスのインスタンスであれば、復元処理の問題は発生しません。
これがTomcatの仕様なのか、作り方がまずいのか はたまたTomcatのバグなのか、判断がつきません。 common/libに配置することなく例外が発生しないようにするには どのように対処すればいいのでしょうか? | ||||
|
投稿日時: 2005-03-14 15:37
ObjectInputStream#resolveProxyClass()はprotectedメソッドなので、
オーバーライドが効きます。 これを自作オーバーライドしたObjectInputStreamサブクラスでオブジェクト の読み込みを行うのが一番手っ取り早そうだと思いますが… | ||||
|
投稿日時: 2005-03-14 15:51
返事ありがとうございます。
ObjectInputStream#resolveProxyClass()の検討もしてみたのですが、 自分で行う場合ではなくTomcatの自動リロード処理の中で行われている為、 自分で生成したObjectInputStreamを使う事ができないですね。 ちなみに書き忘れていましたが、通常のインスタンスとダイナミックプロキシの インスタンスがセッション内に混在していても例外が発生します。 | ||||
|
投稿日時: 2005-03-14 16:20
ぬぬぬ…
動作とソースコードを見る限り、 ObjectInputStream#resolveProxyClass()内部でのlatestUserDefinedLoader() の呼び出しを回避しないとイカンですよね? それが無理となると、Proxyオブジェクトをセッションに格納するのは辞めてしまう、 というのが良さそうですね。そこを回避するわけにはいかないのでしょうか? Proxyをセッションに格納するというのは、どのような理由によるものなのでしょう? | ||||
|
投稿日時: 2005-03-14 16:29
お、今良いことを思いつきました。これ、イケませんか?
1.セッションに直接Proxyオブジェクトをぶら下げるのではなくて、 ラッパーオブジェクトをかますようにする。 public class ProxyWrapper implements Serializable{ private ProxyInterface impl; //getter+setterを実装 } 2.ラッパーオブジェクトのreadObject()、writeObject() を適当にオーバーライドしてしまう。 | ||||
|
投稿日時: 2005-03-14 16:34
あまりスマートな方法ではないですが、
catalina.jarのorg.apache.catalina.util.CustomObjectInputStreamを 修正してうまく動くようになりました。 CustomObjectInputStreamというのはTomcatのWebappClassLoaderを使用して オブジェクトの復元をしてくれるのですが、通常クラスしか解決してくれません。 そこでresolveProxyClass()をオーバーライドして、 スーパークラスの#resolveProxyClass()を呼び出し、 例外が発生したらCustomObjectInputStreamに存在する WebappClassLoaderの参照を使ってProxyクラスのロードを行うようにしました。 根本解決と言えるのか微妙な所ですが・・・ ちなみにソースです。
| ||||
|
投稿日時: 2005-03-14 16:41
投稿と閲覧のタイミングがずれてしまいました。
Proxyをセッションに格納したい経緯です。 DBから値を取得する処理を動的に行っているのですが、 Beanではなくインターフェイスに値を格納したい為です。 別にBeanでもいいのですが、カスタマイズとテストの容易性から インターフェイスを選びました。 #遅いから止めろとか、そういう突っ込みは無しで・・・ [ メッセージ編集済み 編集者: かつのり 編集日時 2005-03-14 16:42 ] | ||||
|
投稿日時: 2005-03-14 16:42
なるほどです。
DynamicProxyは比較的新しい機能であり、どマイナーです ので、Tomcatが対応していなかった。という結論に見えますね。 Jakarta Tomcatに対するソースコミット提案のチャンスかも? |