• 一起谈.NET技术,.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;

            }
        }

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

  • 相关阅读:
    【转】Delphi 关键字详解
    import datetime
    addlayer添加神经网络层
    xadmin使用富文本
    django安装xadmin
    django安装DjangoUeditor富文本
    django中admin一些方法
    Centos7.6安装python3.6.8
    django错误处理
    mysql 快速生成百万条测试数据
  • 原文地址:https://www.cnblogs.com/waw/p/2158732.html
Copyright © 2020-2023  润新知