SqlCenter中的AOP实现
在SqlCenter项目中实现了基于.Net Remoting 透明代理的AOP框架,取得了非常不错的效果.
本文通过验证组件的实现,简单介绍下SqlCenter中AOP 的思想和运用:)
验证组件,为了实现对类属性等的约束和判断的轻量级组件.  比如Filed实体中Name不能为空这个约束.对这个约束的判断就可以通过我们的验证组件实现.  
如果Field属性Name不能为空这个约束,用常规方法实现,则如下:
 public string Name
public string Name {
{ get{return _name;};
get{return _name;}; set
set {
{ if(value!=null)_name=value;
     if(value!=null)_name=value; else _name =" ";
     else _name =" "; };
}; }
}
        这里还是一个最为简单的约束.如果更加复杂呢?同时同种约束的实体很多呢?我们的代码就需要不断的重复.有没有点小孩尿布的味道了?  是的, 我们应该有更好的方案!  
       这个时候,AOP的作用派上了用场.本文假设你对AOP基础理论和对以下知识都有了解:元数据、Attribute、.Net Remoting的代理技术.
从这里你也深入的学习到这些知识:http://www.brucezhang.com/?p=33
下面就我能理解的 "基于AOP的验证组件" 做点分析:)
先看看实现了AOP验证的代码是什么样子的:
 [AspectAttribute]
[AspectAttribute] public class Field : ContextBoundObject
public class Field : ContextBoundObject  {
{ public string Name
   public string Name {
   { get{return _name;}
    get{return _name;} [NotNull]
    [NotNull] set{_name = value;}
    set{_name = value;} /*假设我们还需要他不能为"Randy"
    /*假设我们还需要他不能为"Randy" [NotNull,NotRandy]
    [NotNull,NotRandy] set{_name=value;}
     set{_name=value;} */
    */ }
   } }
}
是不是非常优雅?代码非常清晰,琐碎的约束性判断代码一点都没有,也就一点没有影响核心关注了:)
SqlCenter中的AOP是基于.Net Remoting 代理实现的.
上面代码告诉我们,需要自定义了一个ProxyAttribute,命名为AspectAttribute:
 [AttributeUsage(AttributeTargets.Class)]
[AttributeUsage(AttributeTargets.Class)] public sealed class AspectAttribute : ProxyAttribute
public sealed class AspectAttribute : ProxyAttribute {
{ public override MarshalByRefObject      CreateInstance(Type serverType)
  public override MarshalByRefObject      CreateInstance(Type serverType) {
{ MarshalByRefObject rawInstance =  base.CreateInstance(serverType);
 MarshalByRefObject rawInstance =  base.CreateInstance(serverType); RealProxy rp = new AspectProxy(serverType, rawInstance);
 RealProxy rp = new AspectProxy(serverType, rawInstance); return (MarshalByRefObject) rp.GetTransparentProxy();
 return (MarshalByRefObject) rp.GetTransparentProxy(); }
} }
} 通过MSDN可以知道:
将当前属性应用于需要自定义代理的类型。可以使用 ProxyAttribute 类来截获 new(在 Visual Basic 中为 New)语句,方法是:从 ProxyAttribute 派生,并将该属性置于 ContextBoundObject 的子级上。(不支持将代理属性置于 MarshalByRefObject 的子级上。)
在实现AspectAttribut中有个AspectProxy。这个是? 是的这个就是我们需要透明代理对象。它的实现:
 class AspectProxy : System.Runtime.Remoting.Proxies.RealProxy
class AspectProxy : System.Runtime.Remoting.Proxies.RealProxy 
 {
{ 
 //必须实现 Invoke方法
//必须实现 Invoke方法 
 public override IMessage Invoke(IMessage msg)
public override IMessage Invoke(IMessage msg)  {
{ 
 //InitInterceptors(Init(){})
   //InitInterceptors(Init(){}) 
 //OnBeginInvoke(){Begin(){}}
   //OnBeginInvoke(){Begin(){}} 
 //ExecuteMessage(){}
   //ExecuteMessage(){} 
 //OnCatchException(Catch(){})
   //OnCatchException(Catch(){}) 
 //OnEndInvoke(End(){})
   //OnEndInvoke(End(){}) 
 //OnFinallyInvoke(Finally(){})
   //OnFinallyInvoke(Finally(){}) 
 }
}


通过这样的实现,一个AOP组件框架就出来了! (由于是基于.Net Remoting 的实现,很多烦琐的实现都被屏蔽了,也不需要你理解IL代码了,当然认识本质还是需要的 :) 
那么如何具体的实现一个组件呢?其实也很简单,只要实现了下面这个interface就算搞定了!
{
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
public class ValidateInterceptor : IInterceptor
 {
{
 需要实现IInterceptor接口
      需要实现IInterceptor接口
 //我们关注下 End方法的实现:
//我们关注下 End方法的实现:
 public void End(ref IMethodReturnMessage message)
public void End(ref IMethodReturnMessage message) {
{ object[] attributes = message.MethodBase.GetCustomAttributes(true);
    object[] attributes = message.MethodBase.GetCustomAttributes(true); ValidatedMethod validatedMethod = new ValidatedMethod();
    ValidatedMethod validatedMethod = new ValidatedMethod(); validatedMethod.Init(message.MethodBase, message.ReturnValue, this.target);
    validatedMethod.Init(message.MethodBase, message.ReturnValue, this.target); foreach (object attr in attributes)
    foreach (object attr in attributes) {
    { if (attr is IValidator)
       if (attr is IValidator) {
       { //我们的验证组件Perform方法都得到了实现
              //我们的验证组件Perform方法都得到了实现
 ((IValidator) attr).Perform(validatedMethod);
             ((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 阅读(1882) 评论(7) 收藏 举报
 
                    
                

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号