[Solution] AOP原理解析及Castle、Autofac、Unity框架使用

本节目录:

 

AOP介绍

面向切面编程(Aspect Oriented Programming,英文缩写为AOP),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP是OOP的延续,是软件开发中的一个热点.

常用于:

Authentication 

Caching

Lazy loading

Transactions

 

AOP基本原理

普通类

    class Person : MarshalByRefObject
    {
        public string Say()
        {
            const string str = "Person's say is called";
            Console.WriteLine(str);
            return str;
        }
    }

代理类

    public class Proxy<T> : RealProxy where T : new()
    {
        private object _obj;
        public Proxy(object obj)
            : base(typeof(T))
        {
            _obj = obj;
        }
        public override IMessage Invoke(IMessage msg)
        {
            Console.WriteLine("{0}:Invoke前", DateTime.Now);
            var ret = ((IMethodCallMessage)msg).MethodBase.Invoke(_obj, null);
            Console.WriteLine("{0}:Invoke后", DateTime.Now);
            return new ReturnMessage(ret, null, 0, null, null);
        }
    }

执行

        static void Main(string[] args)
        {
            var per = new Proxy<Person>(new Person()).GetTransparentProxy() as Person;
            if (per != null)
            {
                var str = per.Say();
                Console.WriteLine("返回值:" + str);
            }
            Console.ReadKey();
        }

 

AOP框架

AOP有动态代理和静态IL织入.

本节主要介绍动态代理方式,静态可参考PostSharp.

 

Castle Core

原理:本质是创建继承原来类的代理类.重写虚方法实现AOP功能.

 

只需引用:

Install-Package Castle.Core

(在Castle的2.5以上版本,已经将 Castle.DynamicProxy2.dll 里有内容,集成到 Castle.Core.dll 中。)

 

Simple Class

    public abstract class Person
    {
        public virtual void SayHello()
        {
            Console.WriteLine("我是{0}方法", "SayHello");
        }

        public virtual void SayName(string name)
        {
            Console.WriteLine("我是{0}方法,参数值:{1}", "SayName", name);
        }

        public abstract void AbstactSayOther();

        public void SayOther()
        {
            Console.WriteLine("我是{0}方法", "SayOther");
        }
    }

 

interceptor

    public class SimpleInterceptor : StandardInterceptor
    {
        protected override void PreProceed(IInvocation invocation)
        {
            Console.WriteLine("拦截器调用方法前,方法名是:{0}。", invocation.Method.Name);
        }

        protected override void PerformProceed(IInvocation invocation)
        {
            Console.WriteLine("拦截器开始调用方法,方法名是:{0}。", invocation.Method.Name);
            var attrs = invocation.MethodInvocationTarget.Attributes.HasFlag(MethodAttributes.Abstract);//过滤abstract方法
            if (!attrs)
            {
                base.PerformProceed(invocation);//此处会调用真正的方法 invocation.Proceed();
            }
        }

        protected override void PostProceed(IInvocation invocation)
        {
            Console.WriteLine("拦截器调用方法后,方法名是:{0}。", invocation.Method.Name);
        }
    }

 

Main

        static void Main(string[] args)
        {
            var generator = new ProxyGenerator();       //实例化【代理类生成器】  
            var interceptor = new SimpleInterceptor();  //实例化【拦截器】  

            //使用【代理类生成器】创建Person对象,而不是使用new关键字来实例化  
            var person = generator.CreateClassProxy<Person>(interceptor);

            Console.WriteLine("当前类型:{0},父类型:{1}", person.GetType(), person.GetType().BaseType);
            Console.WriteLine();

            person.SayHello();//拦截
            Console.WriteLine();

            person.SayName("Never、C");//拦截
            Console.WriteLine();

            person.SayOther();//普通方法,无法拦截     
            person.AbstactSayOther();//抽象方法,可以拦截     

            Console.ReadLine();

        }

 

Castle Windsor

特性式AOP

    public interface IPerson
    {
        void Say();
    }

    [Interceptor(typeof(LogInterceptor))]
    public class Person : IPerson
    {
        public void Say()
        {
            Console.WriteLine("Person's Say Method is called!");
        }
    }

 

    public class LogInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("{0}:拦截{1}方法{2}前,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
            invocation.Proceed();
            Console.WriteLine("{0}:拦截{1}方法{2}后,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
        }
    }

 

        static void Main(string[] args)
        {
            using (var container = new WindsorContainer())
            {
                container.Register(Component.For<Person, IPerson>());
                container.Register(Component.For<LogInterceptor, IInterceptor>());
                var person = container.Resolve<IPerson>();
                person.Say();
            }
            Console.ReadKey();
        }


非侵入式AOP

    public interface IPerson
    {
        void Say();
    }

    public class Person : IPerson
    {
        public void Say()
        {
            Console.WriteLine("Person's Say Method is called!");
        }
    }

 

    internal static class LogInterceptorRegistrar
    {
        public static void Initialize(WindsorContainer container)
        {
            container.Kernel.ComponentRegistered += Kernel_ComponentRegistered;
        }

        private static void Kernel_ComponentRegistered(string key, IHandler handler)
        {
            handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(LogInterceptor)));
        }
    }
    public class LogInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("{0}:拦截{1}方法{2}前,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
            invocation.Proceed();
            Console.WriteLine("{0}:拦截{1}方法{2}后,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
        }
    }

 

        static void Main(string[] args)
        {
            using (var container = new WindsorContainer())
            {
                container.Register(Component.For<IInterceptor, LogInterceptor>());//先注入拦截器
                LogInterceptorRegistrar.Initialize(container);
                container.Register(Component.For<IPerson, Person>());
                var person = container.Resolve<IPerson>();
                person.Say();
            }
            Console.ReadKey();
        }

 

Autofac

Install-Package Autofac.Aop

通过特性标签绑定

   class LogInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("{0}:拦截{1}方法{2}前,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
            invocation.Proceed();
            Console.WriteLine("{0}:拦截{1}方法{2}后,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
        }
    }

    public interface IPerson
    {
        void Say();
    }

    [Intercept(typeof(LogInterceptor))]
    public class Person : IPerson
    {
        public void Say()
        {
            Console.WriteLine("Person's Say Method is called!");
        }
    }

 

启用拦截器执行

        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<Person>().As<IPerson>().EnableInterfaceInterceptors();
            builder.RegisterType<LogInterceptor>();
            using (var container = builder.Build())
            {
                container.Resolve<IPerson>().Say();
            }
            Console.ReadLine();
        }

 

或采用非侵入性方法(去掉class上的特性仍可以)

        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<Person>().As<IPerson>().EnableInterfaceInterceptors().InterceptedBy(typeof(LogInterceptor));
            builder.RegisterType<LogInterceptor>();
            using (var container = builder.Build())
            {
                container.Resolve<IPerson>().Say();
            }
            Console.ReadLine();
        }

  

 

Unity

Unity默认提供了三种拦截器:TransparentProxyInterceptor、InterfaceInterceptor、VirtualMethodInterceptor。

TransparentProxyInterceptor:代理实现基于.NET Remoting技术,它可拦截对象的所有函数。缺点是被拦截类型必须派生于MarshalByRefObject。

InterfaceInterceptor:只能对一个接口做拦截,好处时只要目标类型实现了指定接口就可以拦截。

VirtualMethodInterceptor:对virtual函数进行拦截。缺点是如果被拦截类型没有virtual函数则无法拦截,这个时候如果类型实现了某个特定接口可以改用

 

Install-Package Unity.Interception

    public class MyHandler : ICallHandler
    {
        public int Order { get; set; }//这是ICallHandler的成员,表示执行顺序
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.WriteLine("方法执行前");
            //这之前插入方法执行前的处理
            var retvalue = getNext()(input, getNext);//在这里执行方法
            //这之后插入方法执行后的处理
            Console.WriteLine("方法执行后");
            return retvalue;
        }
    }

 

    public class MyHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new MyHandler();//返回MyHandler
        }
    }

 

    public interface IPerson
    {
        void Say();
    }

    [MyHandler]
    public class Person : IPerson
    {
        public virtual void Say()
        {
            Console.WriteLine("Person's Say Method is called!");
        }
    }

 

        static void Main(string[] args)
        {
            using (var container = new UnityContainer())
            {
                container.AddNewExtension<Interception>();
                //1.TransparentProxyInterceptor
                //container.Configure<Interception>().SetInterceptorFor<IPerson>(new TransparentProxyInterceptor());

                //2.InterfaceInterceptor (使用1,2,3均可,这种侵入性最小)
                container.Configure<Interception>().SetInterceptorFor<IPerson>(new InterfaceInterceptor());

                //3.VirtualMethodInterceptor
                //container.Configure<Interception>().SetInterceptorFor<Person>(new VirtualMethodInterceptor());
                container.RegisterType<IPerson, Person>();
                container.Resolve<IPerson>().Say();
            }
            Console.ReadKey();
        }
posted @ 2016-03-08 11:01  Never、C  阅读(5291)  评论(2编辑  收藏  举报