- PR -

Strutsでwar再デプロイするとClassCastException

1
投稿者投稿内容
koe
大ベテラン
会議室デビュー日: 2003/07/13
投稿数: 198
投稿日時: 2004-11-04 20:27
こちらで質問するのは初めてになります。よろしくお願いします。

今、JBoss + Tomcat + Struts + Velocityで開発しています。
Strutsを使用しているwarファイルを、JBossとTomcatを起動したまま再デプロイし、
任意のアクションを実行するとClassCastExceptionが発生して困っています。

SDKと各コンポーネントのバージョンは以下のとおりです。
Sun Java2 SDK 1.4.2_06
JBoss : 3.2.5
Tomcat : 5.0.19 ? JBoss3.2.5に付属のもの
Struts : 1.1
Velocity : 1.4

発生場所は、org.apache.struts.action.RequestProcessor#processActionCreate()
です。ソースの場所は、RequestProcessor.javaの326行目でした。
長くなるのでスタックトレースは省きました。

これはwarの再デプロイに伴いクラスローダが変わった為に起きた問題だろうと
思いますが、どういった対策をしたらいいのかわかりません。

サーバを再起動すれば直りますが、デプロイするたびにサーバを再起動するのは手間がかかり
できれば避けたいです。
この問題について、どなたか対策をご存知の方はいらっしゃいませんか?

なお、デプロイ作業ですが、JBossのserver/default/deployにwarファイルを
コピーする方法で行っています。Tomcat5固有の設定が必要なのでしょうか?
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2004-11-04 20:36
スタックトレースが長いのであれば上の10行〜20行を示すだけでも何かわかるかもしれません。

クラスローダが変化するために発生する ClassCastException なのであれば回避方法は2つあります。
1.より上位のクラスローダで読み込まれるようにする。
再デプロイで破棄されないクラスローダで読み込まれるようにライブラリを配置します。
ただし、依存関係のあるクラスすべて同じ階層で読み込まれるようにするためかなり汚い構造になるかもしれません。
2.オブジェクトとでシリアライズ->シリアライズする
直列化した後復元すればカレントスレッドのコンテキストクラスローダで読み込まれますので ClassCastException は発生いたしません。
#これをやろうとすると Struts にいろいろと手を加えないといけなさそうですが。
koe
大ベテラン
会議室デビュー日: 2003/07/13
投稿数: 198
投稿日時: 2004-11-05 11:34
回答ありがとうございます。スタックトレースですが、以下のようになっています。
log4jのログと合わせて載せます。
コード:
09:42:11,029 ERROR [RequestProcessor] No action instance for path /login could be created
java.lang.ClassCastException
	at org.apache.struts.action.RequestProcessor.processActionCreate(RequestProcessor.java:326)
	at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:268)
	at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
	at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:697)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:810)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
	at filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:176)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:186)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
	at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
	at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
	at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
	at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:72)
	at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
	at org.jboss.web.tomcat.security.JBossSecurityMgrRealm.invoke(JBossSecurityMgrRealm.java:275)
	at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
	at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
	at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
	at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
	at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
	at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
	at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
	at java.lang.Thread.run(Thread.java:534)



件の個所ですが、自作アクションクラスのインスタンスをAction型にキャストして
代入する時にCLlssCastExceptionが発生していました。
これは、自作のアクションクラスがActionを継承していない場合にも発生しますが、
きちんと継承していますし再デプロイ以前は発生しないので、
クラスローダの問題ではないかと思った次第です。

引用:

インギさんの書き込み (2004-11-04 20:36) より:
クラスローダが変化するために発生する ClassCastException なのであれば回避方法は2つあります。
1.より上位のクラスローダで読み込まれるようにする。
2.オブジェクトとでシリアライズ->シリアライズする



1.でできるかどうか調べてみようと思います。2.ですが、インギさんが考えているような
Strutsに手を加える手間を考えると避けたいところです。

ありがとうございました。
koe
大ベテラン
会議室デビュー日: 2003/07/13
投稿数: 198
投稿日時: 2004-11-08 19:56
その後試行錯誤しましてある程度改善しましたので、その報告です。

結局、warを完全にアンデプロイしてから再度デプロイするようにしました。
JBossの場合、warファイルの削除でアンデプロイできるので、
デプロイ前にwarファイルを明示的に削除するようにしました。
こうしたところ、件の例外は発生しなくなりました。
Webアプリケーション丸ごと削除することで古いクラスローダは完全に破棄され、
クラスローダの異なるクラスが同一コンテキスト内に存在しなくなったことで
解決した、と解釈しています。

後出しのようで申し訳ないですが、Eclipse3.0.1とLomboz3.0.1を使用しており、
JBossの起動制御やアプリケーションのデプロイはEclipseおよびAnt経由で行っています。
Lombozを使うと、修正するたびに再デプロイが必要になり不便ですね…。
他にいい方法があればいいのですが。
1

スキルアップ/キャリアアップ(JOB@IT)