Spring Framework 入門記 AOPその9 After Returning Advice
前回はなんとも中途半端に終わらせてしまいました.心より恥じる.
気を取り直して今回は,「5.3.2.4. After Returning advice」へ進みます.
After Returning adviceは,メソッドJoinpointが例外をスローすることなくリターンした場合に呼び出されるAdviceです.
After Returning adviceを実装するには,AfterReturningAdvice
というinterface
をimplements
します.このinterface
は,次のメソッドを持っています.
afterReturning(Object, Method, Object[], Object)
引数はそれぞれ,Joinpointの戻り値,Joinpointメソッド,Joinpointの引数,Joinpointのターゲットであるオブジェクト,です.
Joinpointの戻り値は普通にObject型なので,不変オブジェクトの場合は変更できませんね.コレクションなんかだと変更できるかも(unmodifiable〜でなければ).でも,変更するならやはりAround adviceを使えということだと思われます.
After Returning adviceの使い道ですぐに思いついたのは事後条件です.とはいえ,これもまたAround adviceがあれば済んでしまうというか,@pre
を実現したければAround adviceでなくてはならない感じなんで,やっぱり使い道が... 無念だ.
ともかくですね,近頃は戻り値null
が話題になっている様子.ということで,戻り値null
なんて極悪コードを跳ね飛ばす事後条件をAfter Returning adviceとして作ってみることにしましょう.
こんな感じ.
package study; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class NullNotAllowAfterAdvice implements AfterReturningAdvice { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { assert(returnValue != null); } }
次にこれを適用するターゲット.
package study; public class Foo { public String good() { return "nullなんて戻しません."; } public String bad() { return null; } }
そして定義ファイル.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="foo" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <bean class="study.Foo"/> </property> <property name="interceptorNames"><value>advice</value></property> </bean> <bean id="advice" class="study.NullNotAllowAfterAdvice"> </bean> </beans>
最後に実行用のクラス.
package study; import org.springframework.beans.factory.access.BeanFactoryLocator; import org.springframework.beans.factory.access.BeanFactoryReference; import org.springframework.context.ApplicationContext; import org.springframework.context.access.ContextSingletonBeanFactoryLocator; public class Main { public static void main(String[] args) { try { BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(); BeanFactoryReference ref = locator.useBeanFactory("context"); ApplicationContext context = (ApplicationContext) ref.getFactory(); Foo foo = (Foo) context.getBean("foo"); System.out.println(foo.good()); System.out.println(foo.bad()); ref.release(); } catch (Throwable e) { e.printStackTrace(); } } }
これを実行!!
nullなんて戻しません. null
しまった,assertを有効にしていませんでした.心より恥じる*1.
-ea:study...
を付けて改めて実行!!!
nullなんて戻しません. java.lang.AssertionError at study.NullNotAllowAfterAdvice.afterReturning(NullNotAllowAfterAdvice.java:7) at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:46) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:134) at org.springframework.aop.framework.Cglib2AopProxy.intercept(Cglib2AopProxy.java:144) at study.Foo$$EnhancerByCGLIB$$b893bd2a.bad() at study.Main.main(Main.java:16)
おっけー!
*1:演出じゃありませんよ,本当にやっちゃったんです.決して一日一Zaizenのためにわざとやったのではありません.