zoukankan      html  css  js  c++  java
  • .net中实现AOP(二)

        上篇文章我大概说了一下在.net中如何利用自定义代理类来实现AOP,那篇文章主要说了些原理,这篇我们直接上代码。

         第一:AspectManagedAttribute特性。说到代理机制,那么它直接针对的应该是一个类而不是具体的方法,所以这里我们实现AOP的最小单位就是类,我们定义一个AspectManagedAttribute特性,它标识了具体类会受到AOP管理。
       
         说明:
        
            1:由于这个特性允许标识在类上,所在需要加上[AttributeUsage(AttributeTargets.Class)]。

            2:AOP可以实现多种非业务逻辑的"横切点",这里我们给AspectManagedAttribute增加一个枚举AspectManagedType,这里分为两种:

               1》:普通的异常捕获,当请求的方法抛出异常时,记录在日志中,同时返回空对象。
               2》:在普通异常捕获的基础上,增加方法调用的时间记录。 

    public enum AspectManagedType
        {
            ErrorHandle,
            ElapsedTime
        }
          

             3》:继承ProxyAttribute:指示对象类型需要自定义代理。

             4》:重写ProxyAttribute的方法:MarshalByRefObject CreateInstance(Type serverType)。根据不同的AspectManagedType创建不同的自定义代理类。
            

    代码
    public override MarshalByRefObject CreateInstance(Type serverType)
            {
                MarshalByRefObject mobj 
    = base.CreateInstance(serverType);
                
    if (aspectManaged)
                {
                    RealProxy realProxy 
    = this .GetCurrentRealProxy  (this.aspectManagedType , serverType, mobj);
                    MarshalByRefObject retobj 
    = realProxy.GetTransparentProxy() as MarshalByRefObject;
                    
    return retobj;
                }
                
    else
                {
                    
    return mobj;
                }

            }
            
    private RealProxy GetCurrentRealProxy(AspectManagedType _aspectManagedType, Type serverType, MarshalByRefObject mobj)
            {
                RealProxy real 
    = null;
                
    if (AspectsManager.AspectsProxy.ContainsKey(serverType.Name))
                {
                    
    return AspectsManager.AspectsProxy[serverType.Name];
                }
                
    switch (_aspectManagedType)
                {
                    
    case AspectManagedType .ElapsedTime :
                        real 
    = new AspectProxyElapsedTime(serverType, mobj);
                        
    break;
                    
    case AspectManagedType.ErrorHandle :
                        real 
    = new AspectProxyErrorLog(serverType, mobj);
                        
    break;
                    
    default :
                        real 
    = new AspectProxyErrorLog(serverType, mobj);
                        
    break;
                }
                
    lock (AspectsManager.AspectsProxy)
                {
                    AspectsManager.AspectsProxy.Add(serverType.Name, real);
                }
                
    return real;
            }
      

            5:把所有的CustomProxy放入静态变量中,有小小的性能提升。这里我们创建了AspectsManager,代码比较简单,只包含一个管理器容器。
        

    public  class AspectsManager
     {
      
    public  static Dictionary<string , RealProxy> AspectsProxy = new Dictionary<string , RealProxy>();
     } 

          第二:自定义代理类的实现,这里我就贴异常处理的AspectProxyErrorLog:

          说明:
      
            1:需要继承RealProxy,它提供代理的基本功能。 
            2:重写RealProxy的IMessage Invoke(IMessage msg),对当前实例所表示的远程对象调用在所提供的 IMessage 中指定的方法。

           

    代码
     /// <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 != this.LogManage)
                        {
                            
    this.LogManage.Error(ceha.MethodErrorText + ex.ToString());
                        }
                        methodReturn 
    = new ReturnMessage(null, methodCall);
                    }
                    retMsg 
    = methodReturn;
                }
       
    return retMsg;
      }

          

              3:当捕获到异常后,首先将异常信息写入日志,为了让方法不对外抛出异常,我们可以对返回信息做处理,让它直接返回null。不知道这样做是否妥当,大家多多提意见啊。

       

         第三:.net中要想实现方法的捕获,当然少不了ContextBoundObject:定义所有上下文绑定类的基类。这里我们可以创建一个空类,然后继承ContextBoundObject,客户端的类只需要做下继承就行。
     

    public abstract class AspectObject  : ContextBoundObject
     {
     }

        
          第四:客户端调用。
         
               1:

    [AspectManaged(aspectManagedType=AspectManagedType.ErrorHandle  )]
    public class GetMemberInfoProxy : AspectObject 

               2:如果项目比较多,我们希望把日志能记录到不同的位置,往往我们会创建多个ILog接口,这里可以在方法上下手,创建一个方法级的CoustomerErrorHandle。主要提供如下几个属性:

                  1>:public ILog ILogName { get; set; } 提供自定义的日志接口。当然ILog不能体现在Atttribute中,我们可以采用枚举来替换,然后在后端来动态创建ILog接口。
                  2>:public string MethodElapsedTimeText { get; set; }  方法耗时的提示语。当此参数没有时,默认为方法名。
                  3>: public string MethodErrorText { get; set; } 方法出异常时的提示语。当此参数没有时,默认为方法名。

               3:方法级的示例:

    [CoustomerErrorHandle(MethodElapsedTimeText = "根据会员卡号读取会员信息用时:", MethodErrorText = "根据会员卡号读取会员信息异常:")]
    public MemberInfo GetMemberInfo(long  cardNo)

          总结:

                本人对本篇文章的AOP做了下性能测试,没发现多大的消耗,大家对AOP性能有啥看法,多多指教。

  • 相关阅读:
    python库--pandas--Series.str--字符串处理
    前端--jstree--异步加载数据
    python库--flask--创建嵌套蓝图
    Git--生成公钥和私钥并添加gitlab访问权限
    es查询--请求body
    python生成时间序列(date_range)
    golang使用组合完成伪继承
    golang interface类型的动态绑定
    ruby环境安装草稿
    openfire
  • 原文地址:https://www.cnblogs.com/ASPNET2008/p/1721558.html
Copyright © 2011-2022 走看看