动态织入的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.rarConsoleApplication2.rar

你可能感兴趣的:(AOP)