zoukankan      html  css  js  c++  java
  • AOP在 .NET中的七种实现方法

    这里列表了我想到的在应用程序中加入AOP支持的所有方法。这里最主要的焦点是拦截,因为一旦有了拦截其它的事情都是细节。

    Approach

    方法

    Advantages

    优点

    Disadvantages

    缺点

    Remoting Proxies

    远程代理

    Easy to implement, because of the .Net framework support

    容易实现,因为有.NET框架的支持。

    Somewhat heavyweight
    Can only be used on interfaces or MarshalByRefObjects

    微显重量级

    仅在接口或MarshalByRefObjects 上使用

    Derivingfrom ContextBoundObject

    从ContextBoundObject 派生

    Easiest to implement
    Native support for call interception

    很容易实现

    原生支持调用拦截

    Very costly in terms of performance

    非常昂贵的性能代价

    Compile-time subclassing
    ( Rhino Proxy )

    编译时子类化

    Easiest to understand

    很容易理解

    Interfaces or virtual methods only

    仅用于接口或虚方法

    Runtime subclassing
    ( Castle Dynamic Proxy )

    运行时子类化

    Easiest to understand
    Very flexible

    很容易理解

    非常灵活

    Complex implementation (but alreadyexists)
    Interfaces or virtual methods only

    复杂的实现(已经实现)

    仅用于接口或虚方法

    Hooking into the profiler API
    ( Type Mock )

    分析 API钩子

    Extremely powerful

    极端强大

    Performance?
    Complex implementation (COM API, require separate runner, etc)

    性能未知

    复杂实现(COM API,需要单独运行等)

    Compile time IL-weaving 
    ( Post Sharp / Cecil )

    编译时 IL织入

    Very powerful
    Good performance

    非常强大

    良好的性能

    Very hard to implement

    实现非常困难

    Runtime IL-weaving
    ( Post Sharp / Cecil )

    运行时 IL织入

    Very powerful
    Good performance

    非常强大

    朗好的性能

    Very hard to implement

    实现非常困难

    英文原文 7 Approaches for AOP in .Net

    1.远程代理                                                                                                                           

    使用.Net Remoting/RealProxy

    采用TransparentProxy和RealProxy实现对象的代理,实现思路如下:Client -TransparentProxy - RealProxy - Target Object

    下面实现自定义的TransparentProxy和RealProxy

    using System;
    using System.Runtime.Remoting.Proxies;
    using System.Runtime.Remoting.Messaging;
    
    namespace ConsoleApplication1
    {
        public class User
        {
            public string Name;
            public string PassWord;
        }
    
        //用户注册接口和实现
        public interface IUserProcessor
        {
            void RegUser(User user);
        }
    
        public class UserProcessor : MarshalByRefObject, IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("用户已注册。");
           }
        }
    
        //客户端调用
        class Program
        {       
            static void Main(string[] args)
            {
                try
                {
                    User user = new User() { Name = "lee", PassWord = "123456" };
                    UserProcessor userprocessor = TransparentProxy.Create<UserProcessor>();
                    userprocessor.RegUser(user);
                }
                catch (Exception ex)
                {
                    throw ex;
                }  
                Console.ReadKey();
            }       
        }
    
        //RealProxy  
        public class MyRealProxy<T> : RealProxy
        {
            private T _target;
            public MyRealProxy(T target)
                : base(typeof(T))
            {
                this._target = target;
            }
    
            public override IMessage Invoke(IMessage msg)
            {
                PreProceede(msg);
                IMethodCallMessage callMessage = (IMethodCallMessage)msg;
                object returnValue = callMessage.MethodBase.Invoke(this._target, callMessage.Args);
                PostProceede(msg);
                return new ReturnMessage(returnValue, new object[0], 0, null, callMessage);
            }
            public void PreProceede(IMessage msg)
            {
                Console.WriteLine("方法执行前");
            }
            public void PostProceede(IMessage msg)
            {
                Console.WriteLine("方法执行后");
            }
        }
    
        //TransparentProxy  
        public static class TransparentProxy
        {
            public static T Create<T>()
            {
                T instance = Activator.CreateInstance<T>();
                MyRealProxy<T> realProxy = new MyRealProxy<T>(instance);
                T transparentProxy = (T)realProxy.GetTransparentProxy();
                return transparentProxy;
            }
        }
    }
    View Code

    优点:简单实现

    缺点:性能差

    2. 继承ContextBoundObject方式                                                                                      

    using System;
    using System.Runtime.Remoting.Proxies;
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Activation;
    
    namespace ConsoleApplication4
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine();
                AopClass ap = new AopClass("XiaoQiang");
                Console.WriteLine("Show:" + ap.Hello());
                Console.WriteLine(ap.ToString());
                Console.WriteLine();
    
                Console.WriteLine("Show:" + ap.Say("hello,everybody!"));
                Console.WriteLine(ap.ToString());
                Console.WriteLine(ap.ToString());
                Console.WriteLine();
    
                WatchToDo(ToDoA);
                WatchToDo(ToDoB);
                Console.ReadKey();
    
            }
    
            #region 性能测试
            static void ToDoA()
            {
                ClsA cl1 = new ClsA();
                cl1.ToDo();
            }
            static void ToDoB()
            {
                ClsB cl2 = new ClsB();
                cl2.ToDo();
            }
            static long WatchToDo(Action act)
            {
                System.Diagnostics.Stopwatch stop = new System.Diagnostics.Stopwatch();
                stop.Reset();
                stop.Start();
                for (int i = 0; i < 10000; i++)
                    act();
                stop.Stop();
                Console.WriteLine("Time: " + stop.ElapsedTicks);
                return stop.ElapsedTicks;
            }
            #endregion
        }
    
        #region AopAttribute
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
        public class AopAttribute : ProxyAttribute
        {
            private IAopProxyBuilder builder = null;
            public AopAttribute(Type builderType)
            {
                this.builder = (IAopProxyBuilder)Activator.CreateInstance(builderType);
            }
    
            public override MarshalByRefObject CreateInstance(Type serverType)
            {
                AopProxy realProxy = new AopProxy(serverType);
                return realProxy.GetTransparentProxy() as MarshalByRefObject;
            }
        }
        #endregion
    
        #region MethodAopAdviceAttribute
        [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
        public class MethodAopAdviceAttribute : Attribute
        {
            private AdviceType type = AdviceType.None;
            public MethodAopAdviceAttribute(AdviceType advicetype)
            {
                this.type = advicetype;
            }
    
            public AdviceType AdviceType
            {
                get
                {
                    return this.type;
                }
            }
        }
    
        public enum AdviceType
        {
            None,
            Before,
            After,
            Around
        }
        #endregion
    
        #region AopProxy
        partial interface IAopAction
        {
            void PreProcess(IMessage requestMsg);
            void PostProcess(IMessage requestMsg, IMessage Respond);
        }
    
        public class AopProxy : RealProxy, IAopAction
        {
            public AopProxy(Type serverType)
                : base(serverType)
            { }
    
            public virtual void PreProcess(object obj, string method = "", int argCount = 0, object[] args = null)
            {
                var o = obj as AopClass;
                if (o != null)
                {
                    o.IsLock = false;
                    o.Name = "999999";
                }
            }
    
            public virtual void PreProcess(IMessage requestMsg)
            {
                var o = GetUnwrappedServer();
                IMethodCallMessage call = requestMsg as IMethodCallMessage;
                if (call != null)
                {
                    this.PreProcess(o, call.MethodName, call.InArgCount, call.Args);
                }
                else
                {
                    this.PreProcess(o);
                }
            }
    
            public virtual void PostProcess(object obj, object returnValue = null, string method = "", int argCount = 0, object[] args = null)
            {
                var o = obj as AopClass;
                if (o != null)
                {
                    o.IsLock = true;
                    o.Name = "10101010";
                }
            }
    
            public virtual void PostProcess(IMessage requestMsg, IMessage Respond)
            {
                var o = GetUnwrappedServer();
                ReturnMessage mm = Respond as ReturnMessage;
                var ret = mm.ReturnValue;
                IMethodCallMessage call = requestMsg as IMethodCallMessage;
                if (call != null)
                {
                    this.PostProcess(o, ret, call.MethodName, call.InArgCount, call.Args);
                }
                else
                {
                    this.PostProcess(o, ret);
                }
            }
    
            //public virtual IMessage Proessed(IMessage msg,MarshalByRefObject target)
            //{
            //    IMethodCallMessage call = (IMethodCallMessage)msg;
            //    IConstructionCallMessage ctor = call as IConstructionCallMessage;
            //    if (ctor != null)
            //    {
            //        //获取最底层的默认真实代理  
            //        RealProxy default_proxy = System.Runtime.Remoting.RemotingServices.GetRealProxy(target);
    
            //        default_proxy.InitializeServerObject(ctor);
            //        MarshalByRefObject tp = (MarshalByRefObject)this.GetTransparentProxy();
            //        //自定义的透明代理 this  
    
            //        return System.Runtime.Remoting.Services.EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor, tp);
            //    }
    
            //    IMethodReturnMessage result_msg =  System.Runtime.Remoting.RemotingServices.ExecuteMessage(target, call);
            //    //将消息转化为堆栈,并执行目标方法,方法完成后,再将堆栈转化为消息  
            //    return result_msg;
            //}
    
            public virtual IMessage Proessed(IMessage msg)
            {
                IMessage message;
                if (msg is IConstructionCallMessage)
                {
                    message = this.ProcessConstruct(msg);
                }
                else
                {
                    message = this.ProcessInvoke(msg);
                }
                return message;
            }
    
            public virtual void ChangeReturnValue(IMessage msg, ref object o)
            {
                if (msg is IMethodCallMessage)
                {
                    var m = msg as IMethodCallMessage;
                    string name = m.MethodName;
                    if (name == "Hello")
                        o = "Hello,Lucy!";
                }
            }
    
            public virtual IMessage ProcessInvoke(IMessage msg)
            {
                IMethodCallMessage callMsg = msg as IMethodCallMessage;
                IMessage message;
                try
                {
                    object[] args = callMsg.Args;   //方法参数                 
                    object o = callMsg.MethodBase.Invoke(GetUnwrappedServer(), args);  //调用 原型类的 方法       
                    ChangeReturnValue(msg, ref o);
                    message = new ReturnMessage(o, args, args.Length, callMsg.LogicalCallContext, callMsg);   // 返回类型 Message
                }
                catch (Exception e)
                {
                    message = new ReturnMessage(e, callMsg);
                }
    
                //Console.WriteLine("Call Method:"+callMsg.MethodName);
                //Console.WriteLine("Return:"+ message.Properties["__Return"].ToString());
                return message;
            }
    
            public virtual IMessage ProcessConstruct(IMessage msg)
            {
                IConstructionCallMessage constructCallMsg = msg as IConstructionCallMessage;
                //构造函数 初始化
                IConstructionReturnMessage constructionReturnMessage = this.InitializeServerObject((IConstructionCallMessage)msg);
                RealProxy.SetStubData(this, constructionReturnMessage.ReturnValue);
    
                //Console.WriteLine("Call constructor:"+constructCallMsg.MethodName);
                //Console.WriteLine("Call constructor arg count:"+constructCallMsg.ArgCount);
    
                return constructionReturnMessage;
            }
    
            public override IMessage Invoke(IMessage msg)
            {
                #region  获取AdviceType
                AdviceType type = AdviceType.None;
                IMethodCallMessage call = (IMethodCallMessage)msg;
                foreach (Attribute attr in call.MethodBase.GetCustomAttributes(false))
                {
                    MethodAopAdviceAttribute mehodAopAttr = attr as MethodAopAdviceAttribute;
                    if (mehodAopAttr != null)
                    {
                        type = mehodAopAttr.AdviceType;
                        break;
                    }
                }
                #endregion
    
                IMessage message;
                if (type == AdviceType.Before || type == AdviceType.Around)
                {
                    this.PreProcess(msg);
                    Console.WriteLine("::Before Or Around");
                }
                message = this.Proessed(msg);
                if (type == AdviceType.After || type == AdviceType.Around)
                {
                    this.PostProcess(msg, message);
                    Console.WriteLine("::After Or Around");
                }
                return message;
            }
        }
        #endregion
    
        #region AopProxyBuilder
        public interface IAopProxyBuilder
        {
            AopProxy CreateAopProxyInstance(Type type);
        }
    
        public class AopProxyBuilder : IAopProxyBuilder
        {
            public AopProxy CreateAopProxyInstance(Type type)
            {
                return new AopProxy(type);
            }
        }
        #endregion
    
        #region AopClass
        [AopAttribute(typeof(AopProxyBuilder))]
        public class AopClass : ContextBoundObject
        {
            public string Name
            { get; set; }
    
            public bool IsLock = true;
            public AopClass(string name)
            {
                Name = name;
                Console.WriteLine("Aop Class Create Name:" + Name);
            }
    
            public AopClass()
            {
                Console.WriteLine("Aop Class Create");
            }
    
            [MethodAopAdvice(AdviceType.Around)]
            public string Hello()
            {
                Console.WriteLine("hello world:");
                return "hello world:";
            }
    
            [MethodAopAdvice(AdviceType.Before)]
            public string Say(string content)
            {
                string c = "IsLock:" + IsLock + "	 " + Name + " :" + content;
                Console.WriteLine(c);
                return c;
            }
            public override string ToString()
            {
                return string.Format("Name:{0},IsLock:{1}", this.Name, this.IsLock);
    
            }
        }
        #endregion
    
        #region 测试数据
        public class ClsA
        {
            public void ToDo()
            {
            }
        }
        public class ClsB : ContextBoundObject
        {
            public void ToDo()
            {
            }
        }
        #endregion
    }
    View Code

    测试结果:性能时间后者是前者的318倍

     3.EnterpriseLibary 实现方法                                                                                   

    //首先添加EnterpriseLibary的引用
    
    //自定义CallHandler,这里定义两个CallHandler分别用于参数检查和日志记录。
    
    using Microsoft.Practices.Unity.InterceptionExtension;
    
    public class UserHandler : ICallHandler
    {
        public int Order { get; set; }
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            User user = input.Inputs[0] as User;
            if (user.PassWord.Length < 10)
            {
                return input.CreateExceptionMethodReturn(new UserException("密码长度不能小于10位"));
            }
            Console.WriteLine("参数检测无误");
            return getNext()(input, getNext);
        }
    }
    
    public class LogHandler : ICallHandler
    {
        public int Order { get; set; }
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            User user = input.Inputs[0] as User;
            Log log = new Log() { Message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.PassWord), Ctime = DateTime.Now };
            Console.WriteLine("日志已记录,Message:{0},Ctime:{1}", log.Message, log.Ctime);
            var messagereturn = getNext()(input, getNext);
            return messagereturn;
        }
    }
    
    
    
    //定义对应的HandlerAttribute
    using Microsoft.Practices.Unity.InterceptionExtension;  
    using Microsoft.Practices.Unity;  
      
        public class UserHandlerAttribute : HandlerAttribute  
        {  
            public override ICallHandler CreateHandler(IUnityContainer container)  
            {  
                ICallHandler handler = new UserHandler(){Order=this.Order};  
                return handler;  
            }  
        }  
      
        public  class LogHandlerAttribute:HandlerAttribute  
        {  
            public int Order { get; set; }  
            public override ICallHandler CreateHandler(IUnityContainer container)  
            {  
                return new LogHandler() { Order = this.Order };  
            }  
        }  
    
    
        //用户注册接口和实现,这里通过为接口添加attribute的方式实现。order值表示执行顺序,值小的先执行。
        [LogHandlerAttribute(Order=2)]  
        [UserHandlerAttribute(Order=1)]  
        public interface IUserProcessor  
        {  
             void RegUser(User user);  
        }  
      
        public class UserProcessor : MarshalByRefObject,IUserProcessor  
        {  
            public  void RegUser(User user)  
            {  
                Console.WriteLine("用户已注册。");  
            }  
        }  
    
        //测试
        using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;   
         
        public class Client  
        {  
            public static void Run()  
            {  
                try  
                {  
                    User user = new User() { Name = "lee", PassWord = "123123123123" };  
                    UserProcessor userprocessor = PolicyInjection.Create<UserProcessor>();  
                    userprocessor.RegUser(user);  
                }  
                catch(Exception ex)  
                {  
                    throw ex;  
                }  
            }  
        }  
    View Code

    4.Castle Dynamic Proxy的实现                                                                               

    首先下载Castle.Windsor.dll

    自定义Interceptor

    public class MyInterceptor : IInterceptor
        {
            public void Intercept(IInvocation invocation)
            {
                PreProceed(invocation);
                invocation.Proceed();
                PostProceed(invocation);
            }
            public void PreProceed(IInvocation invocation)
            {
                Console.WriteLine("方法执行前");
            }
     
            public void PostProceed(IInvocation invocation)
            {
                Console.WriteLine("方法执行后");
            }
        }

    用户注册接口和实现

    public interface IUserProcessor
        {
            void RegUser(User user);
        }
     
        public class UserProcessor : IUserProcessor
        {
            public virtual void RegUser(User user)
            {
                Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.PassWord);
            }
        }

    客户端调用

    public class Client
        {
            public static void Run()
            {
                try
                {
                    ProxyGenerator generator = new ProxyGenerator();
                    MyInterceptor interceptor = new MyInterceptor();
                    UserProcessor userprocessor = generator.CreateClassProxy<UserProcessor>(interceptor);
                    User user= new User() { Name = "lee", PassWord = "123123123123" };
                    userprocessor.RegUser(user);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

    6.IL织入 PostSharp实现AOP                                                                                    

    原文链接

    PostSharp简介

    PostSharp是一个用于在.NET平台上实现AOP的框架,是我比较常用的一个AOP框架,官方网站为http://www.sharpcrafters.com。目前最新版本为2.0,但是2.0的license不再免费,因此个人建议下载1.5版,同时下文都是基于PostSharp1.5。

    PostSharp使用静态织入方式实现AOP,其连接点非常丰富,使用简单,而且相对其它一些.NET平台上的AOP框架来说,PostSharp较为轻量级,但是功能却一点也不逊色,因此是我比较喜欢的一个AOP框架。更多关于PostSharp的介绍请参看其官方网站。

    另外使用PostSharp与其它框架不太一样的是一定要下载安装包安装,只引用类库是不行的,因为上文说过,AOP框架需要为编译器或运行时添加扩展。

    使用PostSharp实现AOP示例

    这一节将通过一个例子演示如何使用PostSharp在.NET平台上实现AOP。这个例子将通过AOP为核心业务函数增加日志记录功能。

    新建项目

    首先新建一个C#的WinForm应用程序,如图4所示,这里将工程命名为“PostSharpExample”。

    image

    图4、新建项目

    编写核心业务函数

    首先我们来编写核心业务。当然这里不存在真正的业务,我们只是模拟一个而已。将要模拟的核心业务是预定房间。先构建一个如图5所示的简单UI。

    image

    图5、UI界面

    下面我们为项目增加一个“CoreBusiness”类,并在其中添加“Subscribe”方法。代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    using System;
     
    namespace PostSharpExample
    {
        public class CoreBusiness
        {
            public static void Describe(string memberName, string roomNumber)
            {
                System.Windows.Forms.MessageBox.Show(String.Format("尊敬的会员{0},恭喜您预定房间{1}成功!", memberName, roomNumber), "提示");
            }
        }
    }

    可以看到,这里Subscribe方法仅仅是输出一个提示框。当然,在真正项目中这种输出型代码不应该写在业务逻辑中,这里这样写主要是为了演示方便。然后,我们在Form1中调用Subscribe业务方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    using System;
    using System.Windows.Forms;
     
    namespace PostSharpExample
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
     
            private void BTN_SUBSCRIBE_Click(object sender, EventArgs e)
            {
                if (!String.IsNullOrEmpty(TXB_NAME.Text.Trim()) && !String.IsNullOrEmpty(TXB_ROOM.Text.Trim()))
                    CoreBusiness.Describe(TXB_NAME.Text.Trim(), TXB_ROOM.Text.Trim());
                else
                    MessageBox.Show("信息不完整","提示");
            }
        }
    }

    运行程序就可以看到相应的效果:

    image

    图6、预定房间成功演示效果

    使用AOP增加日志记录功能

    现在加入我们要为程序添加日志功能,记录业务函数的执行情况。这里我们假定需要将日志记录到纯文本文件中,首先我们完成日志记录工具类,LoggingHelper。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    using System;
    using System.IO;
     
    namespace PostSharpExample
    {
        class LoggingHelper
        {
            private const String _errLogFilePath = @"log.txt";
     
            public static void Writelog(String message)
            {
                StreamWriter sw = new StreamWriter(_errLogFilePath, true);
                String logContent = String.Format("[{0}]{1}", DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"), message);
                sw.WriteLine(logContent);
                sw.Flush();
                sw.Close();
            }
        }
    }

    如果不使用AOP,则我们要为包括Subscribe在内的每一个方法在核心业务代码的前后插入日志记录代码(Writelog),我们看看使用PostSharp如何将这种横切关注点分离出来。因为要使用PostSharp,所以要先添加对PostSharp库文件的引用,安装过PostSharp后,在系统可引用项中会多出“PostSharp.Laos”、“PostSharp.Public”和“PostSharp.AspNet”,这里我们做的是Winform程序,所以只需添加对“PostSharp.Laos”和“PostSharp.Public”的引用即可。

    下面我们就要写Aspect了,PostSharp的Aspect是使用Attribute实现的,下面是我实现的日志记录Aspect代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    using System;
    using PostSharp.Laos;
     
    namespace PostSharpExample
    {
        [Serializable]
        [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
        public sealed class LoggingAttribute : OnMethodBoundaryAspect
        {
            public string BusinessName { get; set; }
     
            public override void OnEntry(MethodExecutionEventArgs eventArgs)
            {
                LoggingHelper.Writelog(BusinessName + "开始执行");
            }
     
            public override void OnExit(MethodExecutionEventArgs eventArgs)
            {
                LoggingHelper.Writelog(BusinessName + "成功完成");
            }
        }
    }

    我们约定每个Aspect类的命名必须为“XXXAttribute”的形式。其中“XXX”就是这个Aspect的名字。PostSharp中提供了丰富的内置“Base Aspect”以便我们继承,其中这里我们继承“OnMethodBoundaryAspect ”,这个Aspect提供了进入、退出函数等连接点方法。另外,Aspect上必须设置“[Serializable] ”,这与PostSharp内部对Aspect的生命周期管理有关,具体为什么请参看这里

    我们的LoggingAttribute非常简单,就是在进入(Entry)和离开(Exit)函数时分别记录日志到log文件。现在我们把这个Aspect应用到业务方法上:

    1
    2
    3
    4
    5
    [Logging(BusinessName="预定房间")]
    public static void Describe(string memberName, string roomNumber)
    {
        System.Windows.Forms.MessageBox.Show(String.Format("尊敬的会员{0},恭喜您预定房间{1}成功!", memberName, roomNumber), "提示");
    }

    可以看到,应用Aspect非常简单,就是将相应的Attribute加到业务方法上面。现在我们再运行预定房间程序,结果和上次没什么两样,但是如果我们打开程序目录,会看到多了一个“log.txt”文件,里面记录有类似图7的内容。

    image

    图7、日志内容

    可以看到,我们已经通过AOP实现了日志记录功能。通过AOP将横切关注点分离出来后,日志记录的代码都放在LoggingAttribute里,需要修改只要修改一处即可。同时,业务方法仅含有业务代码,这样大大提高了程序代码的可读性和可维护性。

    对PostSharp运行机制的简要分析

    上文已经说到,PostSharp使用的是静态织入技术,下面我们分析一下PostSharp是如何实现的。

    首先,当安装PostSharp时,它自动为Visual Studio编译器添加了AOP扩展。如果仔细观察PostSharpExample编译信息,会发现有这么两行:

    image

    图8、PostSharp编译信息

    很明显,在.NET Complier编译完成后,下面PostSharp又做了一部分工作,这部分工作就是静态织入的过程。如果我们用.NET Reflector查看PostSharpExample.exe中Subscribe方法的反编译代码,会发现多了很多东西:

    image

    图9、织入Aspect后的Describe代码(由.NET Reflector反编译)

    这些多出来的代码,就是PostSharp静态织入进去的。当然,这些代码在每次编译完成后,PostSharp都会重新织入一次,所以整个过程对程序员是透明的,我们只需维护纯净的业务代码和Aspect代码即可。

    使用PostSharp的优点和缺点(即使用AOP的优点和缺点)

    总体来说,使用PostSharp,将会带来如下优点:

    • 横切关注点单独分离出来,提高了代码的清晰性和可维护性。
    • 只要在Aspect中编写辅助性功能代码,在一定程度上减少了工作量和冗余代码。

    当然,使用PostSharp也不是没有缺点,主要缺点有如下两方面:

    • 增加了调试的难度。
    • 相比于不用AOP的代码,运行效率有所降低。

    所以,对于是否引入AOP,请根据项目具体情况,权衡而定。

    对于PostSharp的进一步学习

    本文只是简要介绍了PostSharp以及实现了一个小例子,并不打算详细完整地介绍PostSharp的方方面面,而只想起到一个抛砖引玉的作用。PostSharp还有非常丰富的功能等待各位学习,因此,如果您对PostSharp十分有兴趣,想进一步学习,请参看PostSharp官方参考文档

    相关下载

    本文用到的Example请点击这里下载。 

    PostSharp1.5安装包请点击这里下载

    5. 各种IoC框架下实现AOP

    首先介绍几种笔者常见的IOC框架

    Unity:微软patterns&practicest团队开发的IOC依赖注入框架,支持AOP横切关注点。
    MEF(Managed Extensibility Framework):是一个用来扩展.NET应用程序的框架,可开发插件系统。
    Spring.NET:依赖注入、面向方面编程(AOP)、数据访问抽象,、以及ASP.NET集成。
    Autofac:最流行的依赖注入和IOC框架,轻量且高性能,对项目代码几乎无任何侵入性。
    Ninject:基于.NET轻量级开源的依赖注入IOC框架

    Castle

    AOP框架

         Encase 是C#编写开发的为.NET平台提供的AOP框架。Encase 独特的提供了把方面(aspects)部署到运行时代码,而其它AOP框架依赖配置文件的方式。这种部署方面(aspects)的方法帮助缺少经验的开发人员提高开发效率。

    NKalore是一款编程语言,它扩展了C#允许在.net平台使用AOP。NKalore的语法简单、直观,它的编译器是基于Mono C#编译器(MCS)。NKalore目前只能在命令行或#Develop内部使用。NKalore兼容公共语言规范CLS(Common Language Specification),它可以在任何.NET开发环境中使用,包括微软的Visual Studio .NET。

    PostSharp读取.NET字节模块,转换成对象模型。让插件分析和转换这个模型并写回到MSIL。PostSharp使开发程序分析应用程序容易得像分析代码规则和设计模式,它使程序开发的思想变革为面向方面软件开发(AOSD/AOD)思想。

     AspectDNG的目标是为.NET开发人员提供简单而功能强大的AOP-GAOP实现。它效仿java下的开源工具AspectJ 和 Spoon,成熟程度也很接近它们。

     RAIL(Runtime Assembly Instrumentation Library) 开源项目可以在C#程序集加载和运行前进行处理控制调整和重新构建。C#在CLR中,我们已经能够动态加载程序集并且获得程序集中的类和方法,RAIL(Runtime Assembly Instrumentation Library)的出现填补了CLR处理过程中的一些空白。

    SetPoint是一款.NET框架下的全功能(full-featured)AOP引擎.它着重为称为语义切点(semantic pointcuts)的定义依赖RDF/OWL的使用.它的功能为一个IL-level,highly dynamic weaver&LENDL,一个引人注目的定义语言、、、、、、

    DotNetAOP为 CLR language提供AOP 框架基础属性。

    NAop是一个DotNet下的AOP框架。

    AspectSharp是DotNet下的免费AOP框架,它以Dynamic Proxies和XML作为配置文件。

    参考文章

    1.Net平台AOP技术研究

    2C#进阶系列——AOP?AOP!

    3.NET中的AOP(厉害啊)

  • 相关阅读:
    CLR自定义菜单项(ToolStripItem)
    WinForm停靠控件介绍:WeifenLuo.WinFormsUI.Docking.dll
    D3D11中的设备介绍
    D3D11 Effect状态的设置
    在写游戏时钟类时,应确保时钟的计算是以某个固定的CPU为标准的
    精确获取时间(QueryPerformanceCounter)
    定点数与浮点数
    error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '0' doesn't match value '2'
    fpu,mmx以及sse寄存器的少量简介
    灵宝方言(超搞笑)
  • 原文地址:https://www.cnblogs.com/code1992/p/9470396.html
Copyright © 2011-2022 走看看