zoukankan      html  css  js  c++  java
  • EnterpriseServerBase的AOP--EsbAOP实现

        EsbAOP是EnterpriseServerBase类库中的轻量级AOP框架,它实现了AOP的主要思想--对方法调用进行截获,并加入自定义的预处理、后处理。 EsbAOP与其它很多开源的AOP实现有些不同,其不同之处主要在于EsbAOP并没有严格的实现AOP理论的各种设施,但是EsbAOP非常实用,在后续的文章中,大家可以看到EsbAOP是如何运用于实际的系统开发中的。

        理解EsbAOP系列文章需要Remoting和消息方面的知识作为基础,如果你以前没有接触过这些内容,可以阅读《.NET 本质论》的第七章。下面就来开始我们的EsbAOP之旅吧。

        既然AOP的核心思想是对方法调用进行截获,并加入自定义的预处理、后处理,那么我们可以很直观的定义出IAspect(方面)接口。而“特定方面”就是实现了IAspect接口的类,什么是“特定方面”?“特定方面”就是完成某一特定目的的一个Aspect,比如权限方面的特定目的就是进行权限管理。即,一个特定的方面,就代表了一个特定目的的前处理和后处理!

        public interface IAspect
        {    
            
    void PreProcess(IMethodCallMessage requestMsg ,object aspectClassArgument ,object aspectMethodArgument) ;
                
            
    void PostProcess(IMethodCallMessage requestMsg ,ref IMethodReturnMessage respond ,object aspectClassArgument ,object aspectMethodArgument) ;    
        }

       
        其中参数requestMsg表示方法调用的请求消息,而respond表示方法调用的结果。注意,如果目标方法在运行的过程中抛出了一个异常,那么该异常也表现为一个IMethodReturnMessage消息。注意,respond参数加上了ref关键字,表示EsbAOP不仅可以截获方法调用,而且还能改变方法运行的结果,这是多么神奇的功能啊!
        另外还有两个参数aspectClassArgument和aspectMethodArgument,为了更方便地说明它们的作用,非得举个例子不可,如下一个应用权限Aspect的例子。

        [Aspect(typeof(PermissionAspectWrap) )]        
        
    public class Example :ContextBoundObject
        {        
            
           
     [AspectSwitcher(typeof(PermissionAspectWrap) ,true ,Permission.Super)]        
            
    public void SayHello(string name)
            {
                Console.WriteLine(
    "Hello ," + name) ;
            }
       
     }

        方法上有个AspectSwitcher特性,它的第三个参数就是aspectMethodArgument。在本例中,这个参数规定了调用SayHello方法所需要的权限是Super。而aspectClassArgument参数位于PermissionAspectWrap的包装之中,它主要用于特定的方面(本例中是PermissionAspect)在执行预处理/后处理时所需要的设施,比如本例中,PermissionAspect就需要通过aspectClassArgument传入一个IPermissionVerifier引用,这个IPermissionVerifier用于对权限是否满足进行判断。
        看了这段描述,不知道你对这两个参数有点了解了没有,不是太明白也没关系,对它们的认识后面会慢慢清晰起来的。
        
        上面Example类上用的“Aspect”特性,这个特性的定义如下:

        /// <summary>
        
    /// AspectAttribute 把被修饰类的实例委托给代理AspectChainProxy ,如此可以截获被修饰类的方法调用    
       
    /// </summary>
        [AttributeUsage(AttributeTargets.Class ,AllowMultiple = false)]
        
    public class AspectAttribute : ProxyAttribute
        {
            
    private Type[] theAspectProcessorWrapTypes = null ;    

            
    public AspectAttribute(params Type[] wrapTypes)
            {            
                
    this.theAspectProcessorWrapTypes = wrapTypes ;
            }

            
    #region CreateInstance
            
    /// <summary>
            
    ///    获得目标对象的自定义透明代理,该方法由系统调用
            
    /// </summary>
            public override MarshalByRefObject CreateInstance(Type serverType)//serverType是被AopProxyAttribute修饰的类
            {
                
    //未初始化的实例的默认透明代理
                MarshalByRefObject target =  base.CreateInstance (serverType); //得到未初始化的实例(ctor未执行)
                object[] args = {target ,serverType} ;
               
                
                
    //得到自定义的真实代理
                RealProxy rp = new AspectChainProxy(target ,serverType ,this.theAspectProcessorWrapTypes) ;//new AopControlProxy(target ,serverType) ;
                return (MarshalByRefObject)rp.GetTransparentProxy() ;
            }
            
    #endregion
        }    


        可以看到,该特性的主要任务是把目标实例委托给AspectChainProxy代理,使截获方法调用得以顺利切入!AspectAttribute的构造参数由params修饰,表示其可接受多个参数,每一个参数对应这一个特定目的的方面(最终,AspectAttribute把这些参数传给了AspectChainProxy代理),这表示前面的例子中可以这样:

        [AspectAttribute(typeof(PermissionAspectWrap) ,typeof(ExceptionLoggerAspectWrap))]        
        
    public class Example :ContextBoundObject

        这样就在Example类上运用了两个方面,一个用于权限管理,一个用于异常日志。

        AspectChainProxy代理用于管理所有运用于目标类(如上面的Example类)上的所有方面,使在运行时,CLR能调用所有方面的前处理和后处理,AspectChainProxy实现如下:

        public class AspectChainProxy: RealProxy 
        {
            
    private MarshalByRefObject target           = null;
            
    private Type[] theAspectProcessorWrapTypes = null;
            
    private ArrayList aspectCallerList         = new ArrayList() ;//集合中为AspectCaller实例
        

            
    public AspectChainProxy(MarshalByRefObject target ,Type serverType ,params Type[] aopProcessorWrapTypes): base(serverType)
            {
                
    this.target = target;
                
    this.theAspectProcessorWrapTypes = aopProcessorWrapTypes ;            
            }

            
    #region Invoke
            
    public override IMessage Invoke(IMessage msg)
            {                    
                IMethodCallMessage call 
    = (IMethodCallMessage)msg ;
                
    this.FillAspectCallerList(call) ;                

                
    //如果触发的是构造函数,此时target的构建还未开始
                IConstructionCallMessage ctor = call as IConstructionCallMessage ;
                
    if(ctor != null)
                {
                    
    //获取最底层的默认真实代理
                    RealProxy default_proxy = RemotingServices.GetRealProxy(this.target) ;

                    default_proxy.InitializeServerObject(ctor) ;
                    MarshalByRefObject tp 
    = (MarshalByRefObject)this.GetTransparentProxy() ; //自定义的透明代理 this

                    
    return EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor,tp);                
                }    
            
                
    this.PreProcess(call) ;
                
                IMethodReturnMessage result_msg 
    = RemotingServices.ExecuteMessage(this.target ,call) ; //将消息转化为堆栈,并执行目标方法,方法完成后,再将堆栈转化为消息
                
                
    this.PostProcess(call ,ref result_msg) ;
                
                
    return result_msg ; 
            }    
            
    #endregion

            
    #region FillAspectCallerList
            
    private void FillAspectCallerList(IMethodCallMessage call)
            {
                
    this.aspectCallerList.Clear() ;

                
    if(this.theAspectProcessorWrapTypes == null)
                {
                    
    return ;
                }

                
    //显式启动了方面的WrapType
                ArrayList overtWrapTypeList = new ArrayList() ;
                

                
    //查询目标方法是否 "显式" 启用AOP的MethodAopSwitcherAttribute
                foreach(Attribute attr in call.MethodBase.GetCustomAttributes(false))
                {
                    AspectSwitcherAttribute aspectSwitcher 
    = attr as AspectSwitcherAttribute ;
                    
    if(aspectSwitcher == null)
                    {
                        
    continue ;
                    }                

                    
    if(aspectSwitcher.DestAspectProcessorWrapType == null)
                    {
                        
    continue ;
                    }    

                    overtWrapTypeList.Add(aspectSwitcher.DestAspectProcessorWrapType) ;

                    
    if (! aspectSwitcher.UseAspect)
                    {
                        
    continue ;
                    }

                    IAspectProcessorWrap processorWrap 
    =  this.GetAspectProcessorWrap(aspectSwitcher.DestAspectProcessorWrapType);
                    
    if(processorWrap == null)
                    {
                        
    continue ;
                    }

                    AspectCaller caller         
    = new AspectCaller() ;
                    caller.AspectMethodArgument 
    = aspectSwitcher.AopArgument ;
                    caller.CurProcessorWrap     
    = processorWrap ;

                    
    this.aspectCallerList.Add(caller) ;
                }

                
    //非显式启用的方面
                foreach(Type wrapType in this.theAspectProcessorWrapTypes)
                {
                    
    bool passIt = this.WrapTypeIsInOvertWrapTypeList(wrapType ,overtWrapTypeList) ;

                    
    if(! passIt)
                    {
                        IAspectProcessorWrap processorWrap 
    = (IAspectProcessorWrap)Activator.CreateInstance(wrapType) ;
                        
    if(processorWrap.DefaultAspectSwitcherState == AspectSwitcherState.On)
                        {
                            AspectCaller caller         
    = new AspectCaller() ;                        
                            caller.CurProcessorWrap     
    = processorWrap ;

                            
    this.aspectCallerList.Add(caller) ;
                        }
                    }
                }
            }

            
    private bool WrapTypeIsInOvertWrapTypeList(Type wrapType ,ArrayList overtWrapTypeList)
            {
                
    foreach(Type tempWrapType in overtWrapTypeList)
                {
                    
    if(wrapType == tempWrapType)
                    {
                        
    return true ;
                    }
                }

                
    return false ;
            }
            
    #endregion
        
            
    #region GetAspectProcessorWrap
            
    private IAspectProcessorWrap GetAspectProcessorWrap(Type aspectProcesserWrapType)
            {
                
    foreach(Type wrapType in this.theAspectProcessorWrapTypes)
                {
                    
    if(wrapType == aspectProcesserWrapType)
                    {
                        IAspectProcessorWrap wrap 
    = (IAspectProcessorWrap)Activator.CreateInstance(wrapType) ;
                        
    return wrap ;
                    }
                }

                
    return null ;
            }
            
    #endregion

            
    #region PreProcess ,PostProcess
            
    private void PreProcess(IMethodCallMessage requestMsg)
            {
                
    foreach(AspectCaller caller in this.aspectCallerList)
                {
                    IAspect aspectProcessor 
    = (IAspect)Activator.CreateInstance(caller.CurProcessorWrap.AspectProcessorType) ;                
                    
    if(aspectProcessor != null)
                    {                    
                        aspectProcessor.PreProcess(requestMsg ,caller.CurProcessorWrap.AspectClassArgument ,caller.AspectMethodArgument) ;
                    }
                }
            }

            
    private void PostProcess(IMethodCallMessage requestMsg, ref IMethodReturnMessage respond)
            {
                
    foreach(AspectCaller caller in this.aspectCallerList)
                {
                    IAspect aspectProcessor 
    = (IAspect)Activator.CreateInstance(caller.CurProcessorWrap.AspectProcessorType) ;
                    
    if(aspectProcessor != null)
                    {                    
                        aspectProcessor.PostProcess(requestMsg ,
    ref respond ,caller.CurProcessorWrap.AspectClassArgument ,caller.AspectMethodArgument) ;
                    }
                }
            }
            
    #endregion        
        }
        
        
    /// <summary>
        
    /// AspectCaller 针对某一特定的方法,实施的一次Aspect调用
        
    /// </summary>
        public class AspectCaller
        {
            
    public IAspectProcessorWrap CurProcessorWrap     = null ;
            
    public object               AspectMethodArgument = null ;
        }


        AspectChainProxy的第四个构造参数正是从AspectAttribute传递过来的,这个参数包含了运用于目标类的所有特定方面的相关信息。AspectChainProxy的核心方法是Invoke方法,该方法由CLR在进入截获阶段时调用。Invoke方法的流程一目了然。
        上文已经有几个地方已经涉及了IAspectProcessorWrap 接口了,正如其名,它是一个包装,包装中的主要内容是一个Asepect,以及提供与该Aspect相关的其它信息。

    /// <summary>
        
    /// IAspectProcessorWrap 对某一Aspect类型和对应的AspectClassArgument进行封装
        
    /// </summary>
        public interface IAspectProcessorWrap
        {
            Type   AspectProcessorType{
    get ;} //返回的是IAspect的实现
            object AspectClassArgument{get ;}
            
            
    /// <summary>
            
    /// 当一个方法没有被某个方面的AspectSwitcherAttribute修饰时,是否启用该方面
            
    /// </summary>
            AspectSwitcherState DefaultAspectSwitcherState{get ;} 
        }


        注释已经很好的解释了IAspectProcessorWrap 接口的方方面面,到这里,你也许发现了,AspectAttribute的构造参数就是实现了IAspectProcessorWrap 的类型。一个特定目的方面(如PermissionAspect)就对应着一个包装(PermissionAspectWrap)。

        关于这个轻量级的AOP实现,还有一个基础设施没有介绍,那就是AspectSwitcherAttribute,这也是一个特性,主要用于修饰方法。它的目的有两个:
    (1)决定被修饰方法针对某特定方面是否启用截获。比如当Example类上使用权限Aspect时,对每个方法的调用都将进行权限判断,然而有些方法调用可能是不需要权限判断的,这种一锅端的做法存在很多AOP实现中,而EsbAOP通过AspectSwitcherAttribute很好的解决了这个问题。并且,IAspectProcessorWrap 接口的DefaultAspectSwitcherState属性更是对此支持的增强。
    (2)传递前述的aspectMethodArgument给预处理和后处理。这个前面已经见过了。

        AspectSwitcherAttribute的定义如下:

        [AttributeUsage(AttributeTargets.Method ,AllowMultiple = true )]
        
    public class AspectSwitcherAttribute : Attribute
        {
            
    private bool   useAspect = false ;
            
    private object theAopArgument = null ;
            
    private Type   destAspectProcessorWrapType = null ;

            
    public AspectSwitcherAttribute(Type destAspectWrapType ,bool useAop)
            {                    
                
    this.destAspectProcessorWrapType = destAspectWrapType ;
                
    this.useAspect                     = useAop ;
            }

            
    public AspectSwitcherAttribute(Type destAspectWrapType ,bool useAop ,object aopArg)
            {            
                
    this.useAspect                     = useAop ;
                
    this.theAopArgument                 = aopArg ;
                
    this.destAspectProcessorWrapType = destAspectWrapType ;
            }

            
    public bool UseAspect
            {
                
    get
                {
                    
    return this.useAspect ;
                }
            }

            
    public object AopArgument
            {
                
    get
                {
                    
    return this.theAopArgument ;
                }
            }

            
    public Type DestAspectProcessorWrapType
            {
                
    get
                {
                    
    return this.destAspectProcessorWrapType ;
                }
            }
        }

        
    public enum AspectSwitcherState
        {
            On ,Off
        }


        EsbAOP的所有实现就介绍完了,如果讲述有不清楚的地方,请留言,我会根据反馈进行修改。在后续的文章中,将在EsbAOP的基础上开展AOP应用,比如权限管理、异常日志、异常关闭器......。

  • 相关阅读:
    opencv目录
    qt5-编译并添加opencv库
    java版gRPC实战之二:服务发布和调用
    java版gRPC实战之一:用proto生成代码
    github搜索技巧小结
    client-go实战之五:DiscoveryClient
    client-go实战之四:dynamicClient
    client-go实战之三:Clientset
    client-go实战之二:RESTClient
    client-go实战之一:准备工作
  • 原文地址:https://www.cnblogs.com/zhuweisky/p/245578.html
Copyright © 2011-2022 走看看