0

編集:質問に技術的な詳細が欠けている可能性があるため、変更を加えました

この問題は Struts 1.3.x で発生し、次のように説明されています。

Struts に関連するクラス (たとえば、ActionForm、Action、および/またはそれらで使用するクラス) を変更すると、変更をテストすると ( webapp を再起動せずに) ClassCastException が発生します。

同じ変更を行った後に webapp を再起動すると、例外はなく、テスト時に変更が表示されます。

この動作は、次の理由から正常であると言われています。

私の Web コンテナー (weblogic) は、変更が加えられた場合にサーブレットとクラスをリロードするように構成されています

クラスに変更が加えられると、別の ClassLoader が使用されると思います。これにより、ClassCastException が発生する可能性があります。

したがって、ソースの変更をテストするたびに webapp を再起動する必要があります...

私が知りたいのは、この種の ClassCastException を回避するため、または webapp を再起動して変更を表示することを回避するために何ができるか (プログラミング パターン?ベスト プラクティス?) です。

スタック トレースは次のとおりです。

java.lang.ClassCastException: my.package.here.MyActionClassNameHere
    at org.apache.struts.chain.commands.servlet.CreateAction.getAction(CreateAction.java:65)
    at org.apache.struts.chain.commands.AbstractCreateAction.execute(AbstractCreateAction.java:91)
    at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)
    at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)
    at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:305)
    at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)
    at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)
    at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1914)
    at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:463)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:821)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3650)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2174)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1446)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

JRebelについてのページを見てきました。それは解決策かもしれませんが、私の目的のためにそれを使用する準備ができていません (これは、Struts 1.3.x を使用した非常に単純なテストです)。

この例外についてもう少し理解するために、いくつかの並行テストを続けます...

4

2 に答える 2

1

これは、ある時点でクラスのインスタンスが 2 つの別個のクラスローダーにロードされている場合に発生するリスクです。http://zeroturnaround.com/blog/reloading-objects-classes-classloaders/を参照して、ClassCastException を探してください。この記事では、Java でのクラス ローディングの核心を非常によく説明しています。

JRebel 以外のソリューションについては、おそらくアプリケーションを再デプロイできます。アプリケーションは十分に小さいので、それほど時間はかからないはずだとおっしゃいました。

于 2012-07-25T08:07:00.227 に答える
0

デフォルトでは、Struts 1.3 (最新の 1.3.x) は、パフォーマンスを最適化するためにアクション クラスをキャッシュに入れます (デプロイメントを再起動すると、キャッシュが消去されます)。これが例外の原因でした。これは、変更したクラスが、キャッシュにあった以前のクラスローダーとは異なるクラスローダーによって読み込まれたためです。

この例外は、アクション インスタンスを取得するステップ中に発生します (これは、スタック トレースでここから始まります)。

at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)

デフォルトでは、このバージョンの Struts は、一連の責任パターンを実装します(xml 構成ファイル chain-config.xml を使用)。したがって、上記のリクエスト プロセッサは、アクション インスタンスの取得 (またはインスタンス化) をCreationAction実装 (ここでは stactrace に示されています) に委譲します。

at org.apache.struts.chain.commands.servlet.CreateAction.getAction(CreateAction.java:65)

以下は、変更を行い、デプロイを再開したくない場合に ClassCastException を回避するためのソリューションです。

解決策 1 :

  • カスタム クラスで CreateAction を拡張し、その getAction() メソッドを再定義します。

  • getAction() 内: super.getAction().getClass()のクラスローダーが新しいものと同じでない場合は、super.createAction( ) を呼び出して新しいインスタンスを返すようにします(つまり、修飾されたクラス名を知っておく必要があります)。 == 演算子を使用して比較するときの Action クラスのそれ以外の場合は、常に createAction を使用して新しいアクション クラスを比較してロードしないでください)。

  • カスタム chain-config.xmlを使用して、デフォルトの代わりにカスタムCreationActionを使用するように指定します

解決策 2 : RequestProcessorをカスタム クラスで拡張し、デフォルトのクラスの代わりに使用します (つまり、struts-config.xml のパラメーターを更新します)。

これらを行うのは開発段階でのみ行うべきであり (テスト時間を節約するため)、パフォーマンス (およびセキュリティ) 上の理由から、運用段階では避けるべきだと思います。

より詳細なサンプル コードや構成ファイルなどを追加する自由な時間がありませんでした...いつか (別の場所で) やってみます。しかし、確かに私はこれらをテストし、それは私の目的のために働いた:)

于 2012-07-28T15:54:59.183 に答える