Re:AspectFlowみたいな。
個人的には Flow よりも Chain かなぁ.
そんなわけで (どんなわけで?),ちょっといかさまな実装.
まずは org.seasar.framework.aop.impl.MethodInvocationImpl
を改造.(^^;
フィールド一つとコンストラクタを追加して,proceed()
を修正してます.
private MethodInvocationImpl parent_; public MethodInvocationImpl(MethodInvocationImpl parent, MethodInterceptor[] interceptors) { parent_ = parent; target_ = parent.target_; method_ = parent.method_; arguments_ = parent.arguments_; interceptors_ = interceptors; targetClass_ = parent.targetClass_; parameters_ = parent.parameters_; } public Object proceed() throws Throwable { while (interceptorsIndex_ < interceptors_.length) { return interceptors_[interceptorsIndex_++].invoke(this); } if (parent_ != null) { return parent_.proceed(); } return methodProxy_.invokeSuper(target_, arguments_); }
そして InterceptorChain クラス.
public class InterceptorChain extends AbstractInterceptor { private MethodInterceptor[] interceptors = new MethodInterceptor[0]; public void add(MethodInterceptor interceptor) { int length = interceptors.length; MethodInterceptor[] newArray = new MethodInterceptor[length + 1]; System.arraycopy(interceptors, 0, newArray, 0, length); newArray[length] = interceptor; interceptors = newArray; } public Object invoke(MethodInvocation invocation) throws Throwable { MethodInvocation myInvocation = new MethodInvocationImpl((MethodInvocationImpl) invocation, interceptors); return myInvocation.proceed(); } }
テスト用の dicon ファイルを用意します.
ここではインターセプタを 3 つ持ったチェーンを一つ定義しています.ターゲットにはチェーンとその前後にインターセプタを定義しています.このため,ターゲットには合計 6 つのインターセプタが適用されていて,そのうちの 5 つが CounterInterceptor
です.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd"> <components> <component name="counter" class="hoge.InterceptorChainTest$CountInterceptor"/> <component name="chain" class="hoge.InterceptorChain"> <initMethod name="add"><arg>counter</arg></initMethod> <initMethod name="add"><arg>counter</arg></initMethod> <initMethod name="add"><arg>counter</arg></initMethod> </component> <component class="hoge.InterceptorChainTest$Foo"> <aspect pointcut="foo">counter</aspect> <aspect pointcut="foo">chain</aspect> <aspect pointcut="foo">counter</aspect> </component> </components>
テストケース.
public class InterceptorChainTest extends S2TestCase { public InterceptorChainTest(String name) { super(name); } public void setUp() { include("InterceptorChainTest.dicon"); } public void test() { CountInterceptor counter = (CountInterceptor) getComponent(CountInterceptor.class); assertEquals(0, counter.count); Foo foo = (Foo) getComponent(Foo.class); foo.foo(); assertEquals(5, counter.count); } public static class Foo { public void foo() { } } public static class CountInterceptor extends AbstractInterceptor { public int count; public Object invoke(MethodInvocation invocation) throws Throwable { ++count; return invocation.proceed(); } } }
一回のメソッド呼び出しで CounterInterceptor
が 5 回呼び出されることを確認しています.
ばっちりでした♪