2、 不同的aspect使用不同的Attribute。此时可以为这些Attribute定义一个共同的抽象基类AOPAttribute:
[AttributeUsage(AttributeTargets.Class)]
public abstract class AOPAttribute:ContextAttribute
{
public AOPAttribute()
: base("AOP")
{
}
public sealed override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
ctorMsg.ContextProperties.Add(GetAOPProperty());
}
protected abstract AOPProperty GetAOPProperty();
}
注:我将GetPropertiesForNewContext()方法sealed,目的是不需要其子类在重写该方法。
继承AOPAttribute类的子类只需要重写GetAOPProperty()方法即可。但在为OrderManager类定义Attribute的时候,需注意其顺序。如以下的顺序:
[AuthorizationAOP]
[AuthenticationAOP]
public class OrderManager{}
此时,AuthorizationAOPAttribute在前,AuthenticationAOPAttribute在后。如果以Decorator的角度来看,对被装饰的方法,AuthorizationAOPAttribute在内,AuthenticationAOPAttribute在外。
考虑到aspect的应用,有的方法需要多个aspect,有的则只需要单个aspect,所以,第二个方案更佳。
五、AOP实例
接下来,我通过一个实例,介绍AOP的具体实现。假定我们要设计一个计算器,它能提供加法和减法功能。我们希望,在计算过程中,能够通过日志记录整个计算过程及其结果,同时需要监测其运算性能。该例中,核心业务是加法和减法,而公共的业务则是日志与监测功能。根据前面对AOP的分析,这两个功能应为我们整个系统需要剥离出来的“方面”。
我们已经拥有了一个AOP实现机制,以及核心的类库,包括AOPSink、AOPProperty、AOPAttribute三个抽象基类。现在,我们分别为日志aspect和监测aspect,定义相应的Sink、Property、Attribute。
首先是日志aspect:
LogAOPSink.cs:
using System;
using System.Runtime.Remoting.Messaging;
using Wayfarer.AOP;
namespace Wayfarer.AOPSample
{
///
/// Summary description for LogAOPSink.
///
public class LogAOPSink:AOPSink
{
public LogAOPSink(IMessageSink nextSink):base(nextSink)
{
}
protected override void AddAllBeforeAOPHandles()
{
AddBeforeAOPHandle("ADD",new BeforeAOPHandle(Before_Log));
AddBeforeAOPHandle("SUBSTRACT",new BeforeAOPHandle(Before_Log));
}
protected override void AddAllAfterAOPHandles()
{
AddAfterAOPHandle("ADD",new AfterAOPHandle(After_Log));
AddAfterAOPHandle("SUBSTRACT",new AfterAOPHandle(After_Log));
}
private void Before_Log(IMethodCallMessage callMsg)
{
if (callMsg == null)
{
return;
}
Console.WriteLine("{0}({1},{2})",callMsg.MethodName,callMsg.GetArg(0),callMsg.GetArg(1));
}
private void After_Log(IMethodReturnMessage replyMsg)
{
if (replyMsg == null)
{
return;
}
Console.WriteLine("Result is {0}",replyMsg.ReturnValue);
}
}
}
LogAOPProperty.cs
using System;
using Wayfarer.AOP;
using System.Runtime.Remoting.Messaging;
namespace Wayfarer.AOPSample
{
///
/// Summary description for LogAOPProperty.
///
public class LogAOPProperty:AOPProperty
{
protected override IMessageSink CreateSink(IMessageSink nextSink)
{
return new LogAOPSink(nextSink);
}
protected override string GetName()
{
return "LogAOP";
}
}
}
LogAOPAttribute.cs:
using System;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Contexts;
using Wayfarer.AOP;
namespace Wayfarer.AOPSample
{
///
/// Summary description for LogAOPAttribute.
///
[AttributeUsage(AttributeTargets.Class)]
public class LogAOPAttribute:AOPAttribute
{
protected override AOPProperty GetAOPProperty()
{
return new LogAOPProperty();
}
}
}
然后再定义监测aspect:
MonitorAOPSink.cs:
using System;
using System.Runtime.Remoting.Messaging;
using Wayfarer.AOP;
namespace Wayfarer.AOPSample
{
///
/// Summary description for MonitorAOPSink.
///
public class MonitorAOPSink:AOPSink
{
public MonitorAOPSink(IMessageSink nextSink):base(nextSink)
{
}
protected override void AddAllBeforeAOPHandles()
{
AddBeforeAOPHandle("ADD",new BeforeAOPHandle(Before_Monitor));
AddBeforeAOPHandle("SUBSTRACT",new BeforeAOPHandle(Before_Monitor));
}
protected override void AddAllAfterAOPHandles()
{
AddAfterAOPHandle("ADD",new AfterAOPHandle(After_Monitor));
AddAfterAOPHandle("SUBSTRACT",new AfterAOPHandle(After_Monitor));
}
private void Before_Monitor(IMethodCallMessage callMsg)
{
if (callMsg == null)
{
return;
}
Console.WriteLine("Before {0} at {1}",callMsg.MethodName,DateTime.Now);
}
private void After_Monitor(IMethodReturnMessage replyMsg)
{
if (replyMsg == null)
{
return;
}
Console.WriteLine("After {0} at {1}",replyMsg.MethodName,DateTime.Now);
}
}
}
MonitorAOPProperty.cs:
using System;
using Wayfarer.AOP;
using System.Runtime.Remoting.Messaging;
namespace Wayfarer.AOPSample
{
///
/// Summary description for MonitorAOPProperty.
///
public class MonitorAOPProperty:AOPProperty
{
public MonitorAOPProperty()
{
//
// TODO: Add constructor logic here
//
}
protected override IMessageSink CreateSink(IMessageSink nextSink)
{
return new MonitorAOPSink(nextSink);
}
protected override string GetName()
{
return "MonitorAOP";
}
}
}
MonitorAOPAttribute.cs:
using System;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Contexts;
using Wayfarer.AOP;
namespace Wayfarer.AOPSample
{
///
/// Summary description for MonitorAOPAttribute.
///
[AttributeUsage(AttributeTargets.Class)]
public class MonitorAOPAttribute:AOPAttribute
{
protected override AOPProperty GetAOPProperty()
{
return new MonitorAOPProperty();
}
}
}
注意在这两个方面中,各自的Property的Name必须是唯一的。
现在,可以定义计算器类。
Calculator.cs:
using System;
namespace Wayfarer.AOPSample
{
///
/// Summary description for Calculator.
///
[MonitorAOP]
[LogAOP]
public class Calculator:ContextBoundObject
{
public int Add(int x,int y)
{
return x + y;
}
public int Substract(int x,int y)
{
return x - y;
}
}
}
需要注意的是Calculator类必须继承ContextBoundObject类。
最后,我们写一个控制台程序来执行Calculator:
Program.cs:
using System;
namespace Wayfarer.AOPSample
{
///
/// Summary description for Class1.
///
class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
Calculator cal = new Calculator();
cal.Add(3,5);
cal.Substract(3,5);
Console.ReadLine();
}
}
}
运行结果如下:
六、结论
在.Net平台下采用动态代理技术实现AOP,其原理并不复杂,而.Net Framework也提供了足够的技术来实现它。如果再结合好的设计模式,提供一个基本的AOP框架,将大大地简化开发人员处理“aspect”的工作。当然,本文虽然提供了实现AOP的实例,但其架构的设计还远远不能达到企业级的要求,如在稳定性、可扩展性上还需经过进一步的测试与改善。例如我们可以通过配置文件的形式,来配置方法与方面之间的映射。同时,由于采用了动态代理,在性能上还期待改进。
使用动态代理技术实现AOP,对实现AOP的类有一个限制,就是必须派生于ContextBoundObject类,这对于单继承语言来说,确实是一个比较致命的缺陷。所谓“仁者见仁,智者见智”,这就需要根据项目的情况,做出正确的抉择了。