[Seasar-s2dotnet 65] s2.NETのAOPの実装について

atsushi fukui atsushi.fukui
2005年 8月 19日 (金) 16:50:27 JST


こんにちは、福井です。

長文で申し訳ありません。(^_^;)

TechEDのNAgile宴会のときに、太一さんからS2.NETのAOP実装についてお話を
聞いて、気になっていた事がありました。ようやく調査する時間ができたので
その結果をご報告します。結論から言うと、S2.NETの現在のAOP実装には少し
考慮すべき点があるように感じています。

下記のテストを実行すると分かりますが、2番目のAssertに失敗します。
これは、thisポインタがHogeImplのインスタンスに対する実参照を返すためで、
これによってAopProxyのコードがバイパスされてしまいます。ターゲットのク
ラスをContextBoundObjectから直接または間接に派生すれば、thisポインタも
TranspaerntProxyポインタとして返すようになりますが、現在のS2.NETの実装
では(ContextAttribute内で作成されるなどの)ContextPropertyによって
IMessageSinkを透過的に挿入しているわけではないので、例えターゲットクラ
スをContextBoundObjectから派生させたとしても自前のRealProxy(AopProxy)
のInvokeが呼び出されるわけではなく、規定のRealProxyが呼び出されるだけ
で、結果は同じです。

container.GetComponent()から取得したオブジェクトがthisポインタを返さな
ければ現在の実装でも問題はないかもしれませんが、これはやはり制限事項で
はないでしょうか。
また本家seasar2の実装では、cglibのEnhancerクラス(2.1系の場合)が動的
に生成するクラスのインスタンスを返しているので、thisポインタ経由でも問
題なくインターセプタが実行されます。2.2系のjavassist版でも構造的には同
じだと思われます。

.NETのRemotingインフラを利用したアスペクトの実装については、
ContextBoundObjectの派生が必要という制限以外にもメッセージ変換に伴うオー
バーヘッドやWindows Communication Foundation(Indigo)との関係も気にな
ります。バージョン 1.0は現在の実装で行っておいて、次のバージョンでは
spring.NETのようにSystem.Reflection.Emit(またはCodeDOM)を使った動的
コード生成の手法への変更も視野に入れても良いのではと私は思いますが、み
なさんはどうでしょうか?

#スミマセン、動的生成の実装についてはこれから勉強します。(^_^;)


[TestFixture]
public class MethodInvocationImplTest2
{
    public interface IHoge
    {
        string Foo();
        IHoge This { get; }
    }

    public class HogeImpl : IHoge
    {
        #region IHoge メンバ

        public string Foo()
        {
            // TODO:  HogeImpl.Foo 実装を追加します。
            Console.WriteLine("Foo");
            return "hogehoge";
        }

        public IHoge This
        {
            get { return this; }
        }

        #endregion
    }

    public class HogeInterceptor : IMethodInterceptor
    {
        public object Invoke(S2.NET.Framework.Aop.IMethodInvocation invocation)
        {
            return "Hello";
        }
    }

    [Test]
    public void TestProceedForAbstractMethod()
    {
        HogeInterceptor interceptor = new HogeInterceptor();
        IPointcut pointcut = new PointcutImpl(new String[]{"Foo"});
        IAspect aspect = new AspectImpl(interceptor, pointcut);
        IHoge h = new HogeImpl();
        AopProxy aopProxy = new AopProxy(
             typeof(IHoge),new IAspect[] { aspect },null, h);
        IHoge proxy = (IHoge) aopProxy.Create();
        
        //成功
        Assert.AreEqual("Hello",proxy.Foo());

        //thisポインタは実参照を返す
        IHoge real = proxy.This;
        
        //このAssertは失敗する
        Assert.AreEqual("Hello", real.Foo());
    }
}

--
福井 厚 Atsushi Fukui
MSMVP Visual Developer - Solutions Architect (Jan 2005)
blog: http://www.users.gr.jp/blogs/fukui/
NAgileで行こう! http://www.fortunatewell.com/



seasar-dotnet メーリングリストの案内