天天看點

動态織入的AOP實作

動态織入的AOP實作,有兩種方法:

第一類,借助于Remoting命名空間下的幾個類,通過擷取目前上下文及反射的機制來實作,這需要被AOP的類需要繼承自

arshalByRefObject

或者ContextBoundObject;

第二類,原理是基于動态代理的思想,即在運作時動态構造一個原有類的子類,這樣就可以在子類的重載方法中插入額外代碼。

這兩類方法,都有顯著的不足,前者直接要求我們繼承固定類,後者呢,除非父類方法被定義為virtual,或者方法定義于某個接口,否則就不能被重載,這就是得“攔截”并不是可以對任意的方法進行的。

動态織入局限于CLR的限制,不能實作對任何方法進行AOP,如果要突破這個限制,隻能采用靜态織入的方法,靜态織入采用。靜态織入突破OO設計模式,可以攔截所有的方法甚至構造函數或屬性通路器,因為它是直接修改IL。還有,因為它在運作前修改原有程式集,也就基本不存在運作時的性能損失問題了。它的不足,一方面是架構較複雜,實作較麻煩,依賴于對底層的IL指令集的操縱;

一:繼承自ContextBoundObject的實作

幫助類:

public class SecurityAspect : IMessageSink
    {
        internal SecurityAspect(IMessageSink next)
        {
            _next = next;
        }

        private IMessageSink _next;

        public IMessageSink NextSink
        {
            get { return _next; }
        }

        public IMessage SyncProcessMessage(IMessage msg)
        {
            Preprocess(msg);
            IMessage returnMethod = _next.SyncProcessMessage(msg);
            return returnMethod;
        }

        public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
        {
            throw new InvalidOperationException();
        }

        private void Preprocess(IMessage msg)
        {
            if (!(msg is IMethodMessage)) 
                return;
            IMethodMessage call = msg as IMethodMessage;
            Type type = Type.GetType(call.TypeName);
            string callStr = type.Name + "." + call.MethodName;
            Console.WriteLine("Security validating : {0} for {1}", callStr,
                Environment.UserName);
            // call some security validating code
        }

    }

    public class SecurityProperty : IContextProperty, IContributeObjectSink
    {
        public IMessageSink GetObjectSink(MarshalByRefObject o, IMessageSink next)
        {
            return new SecurityAspect(next);
        }

        public string Name
        {
            get { return "SecurityProperty"; }
        }
        public void Freeze(Context newContext)
        {
        }
        public bool IsNewContextOK(Context newCtx)
        {
            return true;
        }
    }

    [AttributeUsage(AttributeTargets.All)]
    public class SecurityAttribute : ContextAttribute
    {
        public SecurityAttribute() : base("Security") { }
        public override void GetPropertiesForNewContext(IConstructionCallMessage ccm)
        {
            ccm.ContextProperties.Add(new SecurityProperty());
        }
    }      

調用方:

class Program
    {
        static void Main(string[] args)
        {
            SampleClass s = new SampleClass();
            s.DoSomething();
        }
    }


    [Security]
    [Tracing]
    public class SampleClass: ContextBoundObject
    {
        public void DoSomething()
        {
            Console.WriteLine("do something");
        }
    }      

二:Virtual方法及接口的實作

幫助類:

public class LogHandler : ICallHandler
    {
        /// <summary>
        /// 執行順序
        /// </summary>
        public int Order { get; set; }
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.WriteLine("方法名: {0}", input.MethodBase.Name);
            Console.WriteLine("參數:");
            for (var i = 0; i < input.Arguments.Count; i++)
            {
                Console.WriteLine("{0}: {1}", input.Arguments.ParameterName(i), input.Arguments[i]);
            }
            Console.WriteLine("方法執行前的處理");
            var retvalue = getNext()(input, getNext);
            Console.WriteLine("方法執行後的處理");
            return retvalue;
        }
    }

    public class LogHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new LogHandler();
        }
    }      

調用方:

public interface ISample
    {
        [LogHandler]
        void DoSomething();
        void DoSomethingNoAop();
    }

    class Sample1 : ISample
    {
        public void DoSomething()
        {
            Console.WriteLine("Sample1 do something");
        }

        public void DoSomethingNoAop()
        {
            Console.WriteLine("Sample1 do something no aop");
        }
    }

    public class SampleClass
    {

        [LogHandler]
        public virtual void SampleVirtual()
        {
            Console.WriteLine("Virtual method");
        }

        public void Sample()
        {
            Console.WriteLine("Sampe method");
        }
    }

    class Program {

        static void Main() {
            //針對接口
            var container1 = new UnityContainer()
                .AddNewExtension<Interception>()
                .RegisterType<ISample, Sample1>();
            container1
                .Configure<Interception>()
                .SetInterceptorFor<ISample>(new InterfaceInterceptor());
            container1
                .Configure<Interception>()
                .SetInterceptorFor<SampleClass>(new VirtualMethodInterceptor());
            var sample1 = container1.Resolve<ISample>();
            sample1.DoSomething();
            sample1.DoSomethingNoAop();

            //針對虛拟方法
            var sample2 = container1.Resolve<SampleClass>();
            sample2.SampleVirtual();
            sample2.Sample();

            Console.ReadKey();
        }

    }      

可以看到,第二種方法是用Unity實作的,關于Unity,這裡多說兩句:

Unity的AOP可以從3種标記的情況攔截:

TransparentProxyInterceptor:直接在類的方法上進行标記,但是這個類必須繼承MarshalByRefObject;

VirtualMethod:直接在類的虛方法上進行标記,如上文代碼;

InterfaceInterceptor:在接口的方法上進行标記,如上文代碼;

代碼下載下傳:

ConsoleApplication1.rar

ConsoleApplication2.rar

動态織入的AOP實作

本文基于

Creative Commons Attribution 2.5 China Mainland License

釋出,歡迎轉載,演繹或用于商業目的,但是必須保留本文的署名

http://www.cnblogs.com/luminji

(包含連結)。如您有任何疑問或者授權方面的協商,請給我留言。

繼續閱讀