技术开发 频道

用.NET实现AOP框架


修改BuildUp过程


    如果要修改Builder的装配过程,仅需要增加、维护相关属性即可,例如:
C# 
[Director(3, "BuildPartA")]
[Director(2, "BuildPartB")]
[Director(1, "BuildPartC")]
public class AttributedBuilder : IAttributedBuilder
Unit Test
[TestMethod]
public void Test()
{
IAttributedBuilder builder = new AttributedBuilder();
Director director = new Director();
director.BuildUp(builder);
Assert.AreEqual<string>("a", builder.Log[0]);
Assert.AreEqual<string>("b", builder.Log[1]);
Assert.AreEqual<string>("c", builder.Log[2]);
}
    实际工程中,Attribute常常会和反射、配置一同使用,比如[Director(2, "BuildPartA")]中优先级和方法名称都可以在配置文件定义。虽然看起来开发阶段增加了一些额外的代码工作(例如:Director和DirectorAttribute的编码),但从使用者角度看,减少了反复定义Director相关BuidUp装配的过程。对于其他行为型和结构型模式,Attribute同样可以从很多方面扩展。

应用情景讨论

   上面的示例虽然因为基于专用接口具有很大的局限性,但其实反映了Attirubte方式下AOP开发的一个关键理念——横切,也就是新增的机制游离在业务逻辑之外对业务逻辑发生作用。但如果想让AOP框架更具普适性,就需要把框架和具体类型间的直接调用(包括反射调用)打破,按照面向对象的常规原理,这里需要填补一个新的从客户程序看就是目标对象,但从执行AOP框架看是符合自己需要的新对象出来,为此我们需要通过增加一个所谓“透明代理”的方式完成,这样新的执行流程如下:



    概念上这个透明代理类的主要作用就是把客户程序对目标类型的直接调用拆成两步甚至多步调用,而对客户程序而言他感觉不到这个重发的过程,实际执行步骤相对更为复杂,客户程序调用Transparent Proxy,而Transparent Proxy会调用Real Proxy,Real Proxy后续还可能需要完成一系列Message Sink操作。

    下面是两个更为完整的面向通用类型的AOP实现 (.NET的Attribute和Property一般都译为“属性”,而比较大型的.NET应用中两者又常常同时出现,因此很容易混淆。在同时出现两个概念的时候,本文尽量采用“属性”和“属性方法”分别指向Attribute和Property,尽量避免误会)。

    采用.NET平台自带的AOP机制实现:
    CLR本身对外提供了对AOP机制的支持,不过如用它完成装饰属性则有一个非常不利的限制——客户类型必须继承自MarshalByRefObject 或 ContextBoundObject.。下面是一个示例:
C# 定义装饰属性的基类 
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
abstract class DecoratorAttributeBase : Attribute
{
public abstract void Intercept(object target);
}
C# 定义代理类
class CustomProxy<T> : RealProxy, IDisposable where T : MarshalByRefObject
{
/// 构造过程中把Proxy需要操作的内容与实际目标对象实例Attach到一起。
public CustomProxy(T target) : base(target.GetType()){ AttachServer(target); }
/// 析构过程则借助proxy和目标对象实例的Attach,便于GC回收。
public void Dispose() { DetachServer(); }

public static T Create(T target)
{
if (target == null) throw new ArgumentNullException("target");
return (T)(new CustomProxy<T>(target).GetTransparentProxy());
}

/// 实际执行的拦截,并根据装饰属性进行定制处理。
public override IMessage Invoke(IMessage msg)
{
MethodCallMessageWrapper caller =
new MethodCallMessageWrapper((IMethodCallMessage)msg);
// 提取实际宿主对象
MethodInfo method = (MethodInfo)caller.MethodBase;
T target = (T)GetUnwrappedServer();
DecoratorAttributeBase[] attributes = (DecoratorAttributeBase[])
method.GetCustomAttributes(typeof(DecoratorAttributeBase), true);
if (attributes.Length > 0)
foreach (DecoratorAttributeBase attribute in attributes)
attribute.Intercept(caller);
object ret = method.Invoke(target, caller.Args);
// 拦截处理后,继续回到宿主对象的调用过程
return new ReturnMessage(ret, caller.Args, caller.ArgCount,
caller.LogicalCallContext, caller);
}
}



0
相关文章