Spring has come? その3
今週は仕事場でSpring2.0をいぢりいぢり。
で、DIxAOPコンテナといえばお約束なAOPを使ったログトレース(違っ!w
じゃなくて例外ハンドリングを試してみたら意外に大はまり。
試そうとしていたケースは、
- SpringJDBCを使ったDBアクセスで例外発生(DataAccessException)
- サービスクラスのメソッドをPointcutに指定(ここでハンドリング)
- ハンドリングしてアプリ固有例外として再スロー
- 固有例外をJSF(ManagedBean)でキャッチ
てな感じ。
フレームワーク内で発生した例外をラップしてアプリ(業務)で利用する共通の例外クラスで再スローてのはよくやるパターン。
これをやってみようとしたら、JSF側でキャッチしたら想定外の結果に?
こんな感じでサンプル実装をしてみると…。
/** Pointcutで指定の例外DataAccessExceptionが発生したときの動作 */ @Aspect public class ServiceAspect { @AfterThrowing(value="execution(* hoge.service..*(..))", throwing="dae") public void afterThrowingException(DataAccessException dae) throws Throwable { // SpringJDBCから返されたDataAccessExceptionをラップしたアプリ汎用例外で再スロー throw new ExApplicationException("hoge=" + dae.getLocalizedMessage()); } } /** アプリ共通例外クラス */ public class ExApplicationException extends Throwable { public ExRuntimeException(String string) { super(string); } } /** サービスクラス */ @Transactional public class LoginServiceImpl implements LoginService { public UserDTO login(String username) { if (username != null && username.length() > 0) { // ここで例外DataAccessException発生 return userDao.findByName(username); } return null; } } /** ManagedBean */ public class LoginBean implements Serializable { public String loginAction() { String action = "fail"; try { UserDTO user = loginService.login(this.username); // ここにログインチェックとか action = "success"; } catch (Exception e) { addMessage(new FacesMessage(e.toString())); } return action; } }
期待通り動作してくれるなら、ブラウザ上にメッセージが「hoge=○○○」て出るはずが
「java.lang.reflect.UndeclaredThrowableException」
なぁんてメッセージが��( ̄□ ̄;
はて?
元々例外クラスでThrowableを継承させたのに。
だもんでアプリ例外クラスを
public class ExApplicationException extends DataAccessException { public ExRuntimeException(String string) { super(string); } }
って、SpringJDBCの方から返されるクラスのサブクラスに変更してやってみると「hoge=○○○」て表示される(;´Д`)
いくらなんでもそれは…てことで、Spring1.xのようにインタフェースThrowsAdviceの実装クラスを作成してやってみてもやっぱり同じ結果に。
Spring2.0でAspectJ対応した結果バイトコード変換?するのがcglibになったらしく?
コヤツがなにやら中でUndeclaredThrowableExceptionを返すようにしちゃってるぽい?
(疑問系ばっかw)
てか、ThrowsAdviceの実装クラスでやったときもAspectJ使って動いてるのね。
てっきりapoallianceのほうで動くもんだと思ってたのに…。
AfterThrowingで受けた例外クラスのサブクラスでないと再スローができないってのは、Spring(AspectJ、CGLIB)?の制約、仕様なのか?
これはあんまり逝けてない。
こんだけやって納得いかないもんだからSeasarを使って実験。
→AopProxyTest.java
ちゃんとうごくやぁん_| ̄|○
んー、Springでの使い方が間違ってるのかわからないけど、俺の想定していた使い方ができないとなると結構めんどくさいことに。
実際のアプリ開発でなんど例外ハンドリングで問題になった事やらw
AOP使ってある程度ハンドリングできれば実装に注力できるってのに。
こうしていぢりなから見ていくとシンプルでありながら期待に応えてるSeasarのほうがいいのかも?
戦略次第…難しいなぁ。