态度决定高度、企图决定版图、格局决定结局

导航

SqlCenter中的AOP实现

SqlCenter项目中实现了基于.Net Remoting 透明代理的AOP框架,取得了非常不错的效果.
本文通过验证组件的实现,简单介绍下SqlCenter中AOP 的思想和运用:)

验证组件,为了实现对类属性等的约束和判断的轻量级组件.  比如Filed实体中Name不能为空这个约束.对这个约束的判断就可以通过我们的验证组件实现. 

如果Field属性Name不能为空这个约束,用常规方法实现,则如下:

public string Name
{
get{return _name;};
set
{
     
if(value!=null)_name=value;
     
else _name =" ";
}
;
}

        这里还是一个最为简单的约束.如果更加复杂呢?同时同种约束的实体很多呢?我们的代码就需要不断的重复.有没有点小孩尿布的味道了?  是的, 我们应该有更好的方案! 
       这个时候,AOP的作用派上了用场.本文假设你对AOP基础理论和对以下知识都有了解:元数据、Attribute、.Net Remoting的代理技术.

从这里你也深入的学习到这些知识:http://www.brucezhang.com/?p=33

下面就我能理解的 "基于AOP的验证组件" 做点分析:)

先看看实现了AOP验证的代码是什么样子的:

[AspectAttribute]
public class Field : ContextBoundObject 
{
   
public string Name
   
{
    
get{return _name;}
    [NotNull]
    
set{_name = value;}
    
/*假设我们还需要他不能为"Randy"
    [NotNull,NotRandy]
     set{_name=value;}
    
*/

   }

}

是不是非常优雅?代码非常清晰,琐碎的约束性判断代码一点都没有,也就一点没有影响核心关注了:)

SqlCenter中的AOP是基于.Net Remoting 代理实现的.

上面代码告诉我们,需要自定义了一个ProxyAttribute,命名为AspectAttribute:

[AttributeUsage(AttributeTargets.Class)]
public sealed class AspectAttribute : ProxyAttribute
{
  
public override MarshalByRefObject      CreateInstance(Type serverType)
{
 MarshalByRefObject rawInstance 
=  base.CreateInstance(serverType);
 RealProxy rp 
= new AspectProxy(serverType, rawInstance);
 
return (MarshalByRefObject) rp.GetTransparentProxy();
}

}
 

通过MSDN可以知道:

将当前属性应用于需要自定义代理的类型。可以使用 ProxyAttribute 类来截获 new(在 Visual Basic 中为 New)语句,方法是:从 ProxyAttribute 派生,并将该属性置于 ContextBoundObject 的子级上。(不支持将代理属性置于 MarshalByRefObject 的子级上。)

在实现AspectAttribut中有个AspectProxy。这个是? 是的这个就是我们需要透明代理对象。它的实现:

class AspectProxy : System.Runtime.Remoting.Proxies.RealProxy 



//必须实现 Invoke方法 

public override IMessage Invoke(IMessage msg) 


   
//InitInterceptors(Init(){}) 

   
//OnBeginInvoke(){Begin(){}} 

   
//ExecuteMessage(){} 

   
//OnCatchException(Catch(){}) 

   
//OnEndInvoke(End(){}) 

   
//OnFinallyInvoke(Finally(){}) 

}




通过这样的实现,一个AOP组件框架就出来了! (由于是基于.Net Remoting 的实现,很多烦琐的实现都被屏蔽了,也不需要你理解IL代码了,当然认识本质还是需要的 :)

那么如何具体的实现一个组件呢?其实也很简单,只要实现了下面这个interface就算搞定了!

public interface IInterceptor
{
void Init(object target);
void Begin(IMethodCallMessage call);
void End(ref IMethodReturnMessage message);
void Catch(ref IMethodReturnMessage message);
void Finally(ref IMethodReturnMessage message);
}

就简单看看一个基于当前组件框架的验证组件的实现:

//首先,我们需要定义一个接口来规范验证组件的行为

public interface IValidator
{
           //验证过程写在Perform中

           void Perform(IValidatedElement element);
}

 //比如说NotNull,也就是上文提到的判断属性值不为Null值得组件

public class NotNullAttribute:Attribute,IValidator

{

public void Perform(IValidatedElement element)
{
if(element.Value==null)
{

//可以throw 一个异常
OnFailed(element);
}
OnSucceed(element);
}

}

是不是很简单?再来一个非空字符判断组件(有没有感觉到这个判断过程散布在系统每个角落?)

public class NotWhiteSpaceAttribute:Attribute,IValidator

{

public void Perform(IValidatedElement element)
{
if(element.Value!=null)
{
string value = element.Value as string;
if(value!=null&&value.Trim().Length ==0)
{
OnFailed(element);
}
}
OnSucceed(element);
}

}

这时你也许要问这些组件是如何发挥作用的呢?这个就要提到ValidateInterceptor这个拦截器了!因为只有拦截住对这些加了Attribute的属性的操作过程,才能有效的织入我们的验证.

下面给出它的实现:

public class ValidateInterceptor : IInterceptor

{

      
需要实现IInterceptor接口

//我们关注下 End方法的实现:

public void End(ref IMethodReturnMessage message)
{
    
object[] attributes = message.MethodBase.GetCustomAttributes(true);
    ValidatedMethod validatedMethod 
= new ValidatedMethod();
    validatedMethod.Init(message.MethodBase, message.ReturnValue, 
this.target);
    
foreach (object attr in attributes)
    
{
       
if (attr is IValidator)
       
{
              
//我们的验证组件Perform方法都得到了实现

             ((IValidator) attr).Perform(validatedMethod);
       }

    }

}

}



最后,回过头来看看,我们的NotNull验证组件是如何起作用的:

1.让我们的类继承于ContextBoundObject ,同时加上[AspectAttribute]

2.在我们需要不为null的属性上添加上[NotNull,NotWhiteSpaceAttribute]这个Attribute.

3.运行时:

   系统处理(get,set或方法实现上)遇到这个Attribute时,通过配置文件:

<interceptors>
<add key="ValidateInterceptor" value="SqlCenter.Validators.ValidateInterceptor, SqlCenter.Validators"/>
</interceptors>

发现处理者,并将这个消息加入到拦截器链中,再将任务转交给各自组件去处理(这里似乎也有Ioc思想和策略模式的运用) .

4.处理完成就返回,出现不符合约束要求的就做响应的处理.

上面是关于SqlCenter 中AOP思想的点点理解.

posted on 2006-11-06 21:17  flyingchen  阅读(1868)  评论(7编辑  收藏  举报