SqlCenter中的AOP实现
在SqlCenter项目中实现了基于.Net Remoting 透明代理的AOP框架,取得了非常不错的效果.
本文通过验证组件的实现,简单介绍下SqlCenter中AOP 的思想和运用:)
验证组件,为了实现对类属性等的约束和判断的轻量级组件. 比如Filed实体中Name不能为空这个约束.对这个约束的判断就可以通过我们的验证组件实现.
如果Field属性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验证的代码是什么样子的:
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:
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。这个是? 是的这个就是我们需要透明代理对象。它的实现:
{
//必须实现 Invoke方法
public override IMessage Invoke(IMessage msg)
{
//InitInterceptors(Init(){})
//OnBeginInvoke(){Begin(){}}
//ExecuteMessage(){}
//OnCatchException(Catch(){})
//OnEndInvoke(End(){})
//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的属性的操作过程,才能有效的织入我们的验证.
下面给出它的实现:
{
需要实现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) 编辑 收藏 举报