.net中利用代理实现AOP

      .net中利用代理实现AOP

     上篇文章我说到了在代码中可以利用泛型委托来封装异常处理,这样可以让程序看起来更加清晰,要想完成功能需要调用者调用指定的工厂方法才行,但要想改变某些程序员的编码习惯我想是一件比较困难的事情。有朋友说利用委托来实现异常处理并不算是真正意义上的AOP,因为传统的AOP并不需要客户端做代码结构的变更,最多也就是配置上的问题。但在.net中要想实现AOP,我想最方便的实现机制要属代理机制了,但只要利用代理,在性能上就会造成一定的影响。

      如果开发过分布式服务,像remotion,wcf等,消息都是它们通信的重要手段。客户端通过方法调用形式体现的服务访问需要转换成具体的消息,然后经过编码才能利用传输通道发送给服务端,服务执行的结果也只能以消息的形式返回给调用方。

      这些分布式服务有一共同特点:都通过代理方法间接的调用服务。服务代理,它自身并不提供服务的实现,只是起到一个中介作用,客户端把服务请求发送给服务代理,服务代理再去调真正的服务,同样服务返回时,也是返回给服务代理,再由服务代理返回给客户端。看到这,我想对于实现AOP的拦截就有点眉目了。在.net中,我们可以写自定义的RealProxy来实现AOP的方法拦截功能。     

      服务代理通常又分为以下两种:
  
     1:透明代理。客户端在跨任何类型的远程处理边界使用对象时,对对象使用的实际上是透明代理。透明代理使人以为实际对象驻留在客户端空间中。它实现这一点的方法是:使用远程处理基础结构将对其进行的调用转发给真实对象。透明代理本身由 RealProxy 类型的托管运行时类的实例收容。RealProxy 实现从透明代理转发操作所需的部分功能。代理对象继承托管对象(例如垃圾回收、对成员和方法的支持)的关联语义,可以将其进行扩展以形成新类。这样,该代理具有双重性质,一方面,它需要充当与远程对象(透明代理)相同的类的对象;另一方面,它本身是托管对象。

     2:真实代理。RealProxy来实现与远程服务进行通信,所以这里就是我们实现AOP的地方。

 

     下图是透明代理与真实代理以及远程对象的调用关系图:

                            

 

      下图是利用自定义的RealProxy实现AOP方法拦截的原理图:

 

                           

         自定义异常代理类:

         说明:1>自定义的代理类需要继承RealProxy。

                2>从 RealProxy 继承时,必须重写 Invoke方法。

                3>下面代码中的LogManage是一个log4net接口,我们可以把异常统一记录到日志中,供日后分析。

代码
/// <summary>
    
/// Aspect代理,在这个类里面,实现对方法的拦截
    
/// </summary>
    public class AspectProxyErrorLog : RealProxy    
    {
        AspectManagedAttribute attr;
        
/// <summary>
        
/// 默认构造函数
        
/// </summary>
        public AspectProxyErrorLog() : base()
        {
        }
        
/// <summary>
        
/// 构造函数
        
/// </summary>
        
/// <param name="myType">被代理的类的类型</param>
        public AspectProxyErrorLog(Type myType) : base(myType)
        {
        }
        
/// <summary>
        
/// 构造函数
        
/// </summary>
        
/// <param name="myType">被代理的类的类型</param>
        
/// <param name="obj">被代理的对象</param>
        public AspectProxyErrorLog(Type myType,MarshalByRefObject obj) : base(myType)
        {
            target
=obj;
        }
        MarshalByRefObject target;
        ILog LogManage;
        
/// <summary>
        
/// 当在派生类中重写时,在当前实例所表示的远程对象上调用在所提供的 IMessage 中指定的方法。<br />
        
/// WebsharpAspect在这里执行对方法执行的拦截处理
        
/// </summary>
        
/// <param name="msg">IMessage,包含有关方法调用的信息。</param>
        
/// <returns>调用的方法所返回的消息,包含返回值和所有 out 或 ref 参数。</returns>
        public override IMessage Invoke(IMessage msg)
        {
            IMessage retMsg
=null ;
            IMethodCallMessage methodCall 
= (IMethodCallMessage)msg;
            IMethodReturnMessage methodReturn 
= null;
            
object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[];
            methodCall.Args.CopyTo(copiedArgs, 
0);
            
object[] attrs = null;
            CoustomerErrorHandleAttribute ceha 
= null;
            
if (msg is IConstructionCallMessage)
            {

                IConstructionCallMessage ccm 
= (IConstructionCallMessage)msg;
                RemotingServices.GetRealProxy(target).InitializeServerObject(ccm);
                ObjRef oRef 
= RemotingServices.Marshal(target);
                RemotingServices.Unmarshal(oRef);
                retMsg 
= EnterpriseServicesHelper.CreateConstructionReturnMessage(ccm, (MarshalByRefObject)this.GetTransparentProxy());

            }
            
else
            {
                IMethodCallMessage mcm 
= (IMethodCallMessage)msg;                
                attrs 
= methodCall.MethodBase.GetCustomAttributes(typeof(CoustomerErrorHandleAttribute), false);               
                ceha 
= LogManagerFactory.GetCoustomerErrorHandleAttribute(attrs, methodCall.MethodBase.Name );
                
if (null != ceha)
                {
                    LogManage 
= ceha.ILogName;
                }
                
try
                {
                    
object returnValue = methodCall.MethodBase.Invoke(this.target, copiedArgs);
                    methodReturn 
= new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);
                    
                }
                
catch (Exception ex)
                {
                    
if (null != ex.InnerException)
                    {
                        methodReturn 
= new ReturnMessage(ex.InnerException, methodCall);
                    }
                    
else
                    {
                        methodReturn 
= new ReturnMessage(ex, methodCall);
                    }
                }
                retMsg 
= methodReturn;

            }
            
if (null != methodReturn)
            {
                
if (null != methodReturn.Exception )
                {
                    
if (null != this.LogManage )
                    {
                        
this.LogManage.Error(ceha .MethodErrorText  + methodReturn.Exception.ToString());
                    }

                }
            }
            
return retMsg;

        }
    }

 

 

           上面只是贴了部分代码,在下一篇中,我会对这部分代码做更加详细的分析。

 

posted on 2010-04-25 23:10  min.jiang  阅读(5162)  评论(1编辑  收藏  举报