1、AOP实现初步java
AOP将软件系统分为两个部分:核心关注点和横切关注点。核心关注点更多的是Domain Logic,关注的是系统核心的业务;而横切关注点虽与核心的业务实现无关,但它倒是一种更Common的业务,各个关注点离散地分布于核心业务的多处。这意味着,若是不该用AOP,那么这些横切关注点所表明的业务代码,就会分散在系统各处,致使系统中的每一个模块都与这些业务具备很强的依赖性。在这里,所谓横切关注点所表明的业务,即为“方面(Aspect)”,常见的包括权限控制、日志管理、事务处理等等。 程序员
以权限控制为例,假设一个电子商务系统,须要对订单管理用户进行权限断定,只有系统用户才能添加、修改和删除订单,那么传统的设计方法是:设计模式
public class OrderManager架构
{app
private ArrayList m_Orders;框架
public OrderManager()异步
{ide
m_Orders = new ArrayList();函数
}性能
public void AddOrder(Order order)
{
if (permissions.Verify(Permission.ADMIN))
{
m_Orders.Add(order);
}
}
public void RemoveOrder(Order order)
{
if (permissions.Verify(Permission.ADMIN))
{
m_Orders.Remove(order);
}
}
}
这样的设计其缺陷是将订单管理业务与权限管理彻底结合在一块儿,耦合度高。而在一个系统中,相似的权限控制会不少,这些代码就好像一颗颗毒瘤通常蔓延于系统中的各处,一旦须要扩展,则给程序员们带来的困难是不可估量的。
让咱们来观察一下订单管理业务中的权限管理。不论是添加订单,仍是删除订单,有关权限管理的内容是彻底相同的。那么,为何咱们不能将这些相同的业务,抽象为一个对象,并将其从订单管理业务中彻底剥离出来呢?在传统的OO设计思想,这种设想是不能实现的。由于订单管理业务做为一个类对象,它封装了诸如添加、删除订单等行为。这种封装性,就决定了咱们不可能切入到对象内部,经过获取方法消息的形式,对对象行为进行监控与操做。
AOP的思想解决了这个问题,之因此称为“方面(Aspect)”,就是把这些对象剖开,仅获取其内部相一致的逻辑,并剥离出来,以“方面”的形式存在。要让这些方面可以对核心业务进行控制,就须要有一套获取方法消息的机制。在.Net中,其中一种技术称为动态代理。
在.Net中,要实现动态代理,须要用到.Net Remoting中的消息机制,以及.Net Framework内部提供的ContextAttribute类来自定义本身的Attribute。另外,.Net还要求调用“Aspect”的核心业务类,必须继承ContextBoundObject类。只有这样,咱们才能截取其内部传递的方法消息。如下,是相关接口和类的说明。
ContextAttribute类
该类继承了Attribute类,它是一个特殊的Attribute,经过它,能够得到对象须要的合适的执行环境,即Context(上下文)。它还实现了IContextAttribute和IContextProperty接口。咱们自定义的Attribute将从ContextAttribute类派生。
构造函数:
ContextAttribute类的构造函数带有一个参数,用来设置ContextAttribute的名称。
公共属性:
Name:只读属性。返回ContextAttribute的名称
公共方法:
GetPropertiesForNewContext:虚拟方法。向新的Context添加属性集合。
IsContextOK:虚拟方法。查询客户Context中是否存在指定的属性。
IsNewContextOK:虚拟方法。默认返回true。一个对象可能存在多个Context,使用这个方法来检查新的Context中属性是否存在冲突。
Freeze:虚拟方法。该方法用来定位被建立的Context的最后位置。
ContextBoundObject类
这个类的对象经过Attribute来指定它所在的Context,凡是进入该Context的调用均可以被拦截。该类从MarshalByRefObject派生。
IMessage:定义了被传送的消息的实现。一个消息必须实现这个接口。
IMessageSink:定义了消息接收器的接口,一个消息接收器必须实现这个接口。
该接口主要提供了两个方法,分别进行同步和异步操做:
SyncProcessMessage(IMessage msg):接口方法,当消息传递的时候,该方法被调用;
AsyncProcessMessage(IMessage msg, IMessageSink replySink):该方法用于异步处理;
下面是实现权限控制AOP的简单实现,首先咱们自定义一个Attribute,它继承了ContextAttribute:
[AttributeUsage(AttributeTargets.Class)]
public class AOPAttribute:ContextAttribute
{
public AOPAttribute()
: base("AOP")
{
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
ctorMsg.ContextProperties.Add(new AOPProperty());
}
}
在GetPropertiesForNewContext()方法中,添加了AOPProperty对象,它是一个上下文环境属性:
public class AOPProperty : IContextProperty, IContributeObjectSink
{
public AOPProperty()
{
}
#region IContributeObjectSink Members
public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
{
return new AOPSink(nextSink);
}
#endregion
#region IContextProperty Members
public void Freeze(Context newContext)
{
}
public bool IsNewContextOK(Context newCtx)
{
return true;
}
public string Name
{
get { return "AOP"; }
}
#endregion
AOPProperty属性实现了接口IContextProperty,IContributeObjectSink。GetObjectSink()方法为IContributeObjectSink接口的方法,在其实现中,建立了一个IMessageSink对象AOPSink,该对象实现了IMessageSink接口:
public class AOPSink : IMessageSink
{
private IMessageSink m_NextSink;
public AOPSink(IMessageSink nextSink)
{
m_NextSink = nextSink;
}
public IMessageSink NextSink
{
get { return m_NextSink; }
}
public IMessage SyncProcessMessage(IMessage msg)
{
IMethodCallMessage call = msg as IMethodCallMessage;
if (call == null)
{
return null;
}
IMessage retMsg = null;
if (call.MethodName == "AddOrder" || call.MethodName == "DeleteOrder")
{
if (permissions.Verify(Permission.ADMIN))
{
retMsg = m_NextSink.SyncProcessMessage(msg);
}
}
return retMsg;
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
return null;
}
}
在AOPSink中,最重要的是SyncProcessMessage()方法,在这个方法中,实现了权限控制,并经过IMessage,截取了须要权限控制的方法。在检验了权限以后,而后再执行OrderManager的AddOrder和DeleteOrder方法。
经过AOP的实现,原来的OrderManager,就能够修改成:
[AOP]
public class OrderManager: ContextBoundObject
{
private ArrayList m_Orders;
public OrderManager()
{
m_Orders = new ArrayList();
}
public void AddOrder(Order order)
{
m_Orders.Add(order);
}
public void RemoveOrder(Order order)
{
m_Orders.Remove(order);
}
}
在上述的OderManager类中,彻底消除了permissions.Verify()等有关权限的代码,解除了订单管理与权限管理之间的耦合。
2、与AspectJ比较
上述的方案虽然解除了订单管理与权限管理的耦合,但从SyncProcessMessage()方法能够看出,它的实现具备很大的局限性。试想一下这样的应用场景,在订单管理系统中,用户要求对修改订单的方法增长权限验证,同时要求在验证权限时,容许业务经理(Permission.Manager)也具有管理订单的权限,应该怎样作?仔细思考,咱们会发觉以上的实现未免太过死板了。
让咱们来参考一下AspectJ在java中的实现。AspectJ提供了本身的一套语法,其中包括aspect、pointcut、before、after等。咱们能够经过aspect定义一个“方面”,如上的权限管理:
private static aspect AuthorizationAspect{……}
pointcut为切入点,在其中定义了须要截取上下文消息的方法,例如:
private pointcut authorizationExecution():
execution(public void OrderManager.AddOrder(Order)) ||
execution(public void OrderManager.DeleteOrder(Order)) ||
execution(public void OrderManager.UpdateOrder(Order));
因为权限验证是在订单管理方法执行以前完成,所以在before中,定义权限检查:
before(): authorizationExecution()
{
if !(permissions.Verify(Permission.ADMIN))
{
throw new UnauthorizedException();
}
}
从上述AspectJ的实现中,咱们能够看到,要定义本身的aspect是很是容易的,而经过pointcut的方式,能够将须要截取消息的方法,集中在一块儿。before和after则是具体的方面执行的逻辑,它们就好像Decorator模式那样,对原有方法进行了一层装饰,从而达到将aspect代码植入的目的。
另外,AspectJ还提供了更简单的语法,能够简化前面pointcut中一系列方法的列举:
private pointcut authorizationExecution():
execution (public * OrderManager.*(.))
AspectJ在应用AOP领域,已经很是成熟。它提供了自成一体的特有AspectJ语法,并须要专门的java编译器,使用起来较为复杂。那么,在.Net下,能否实现相似AspectJ的功能呢?我想,因为.Net与java在不少技术的类似性,它们彼此之间在不少领域是相通的,所以要达到这一目标应该是可行的。事实上,开源项目中的Aspect#,就与AspectJ类似。
事实上,若是咱们利用前面描述的动态代理机制,辅以设计模式的OO设计方法,直接在代码中也能够实现AspectJ中的部分AOP特性。
3、.Net中AOP的深刻实现
咱们先分析AspectJ中的pointcut和.Net中的SyncProcessMessage()方法。Pointcut能够添加一系列须要截取上下文的方法,那么在.Net中,咱们也能够利用集合,动态地添加方法,并建立这些方法与“方面”的映射。一样的,AspectJ中的before和after,是“方面”的核心实现,那么在.Net中,咱们也能够利用委托,使其对应相关的方法,来实现其核心逻辑。
结合动态代理的知识,咱们先定义两个委托,分别表明before和after操做:
public delegate void BeforeAOPHandle(IMethodCallMessage callMsg);
public delegate void AfterAOPHandle(IMethodReturnMessage replyMsg);
BeforeAOPHandle中的参数callMsg,其值为要截取上下文的方法的消息;AfterAOPHandle中的参数replyMsg,则是该方法执行后返回的消息。
接下来,定义一个抽象基类AOPSink,它实现了IMessageSink接口:
public abstract class AOPSink : IMessageSink
{
private SortedList m_BeforeHandles;
private SortedList m_AfterHandles;
private IMessageSink m_NextSink;
}
在类AOPSink中,定义了两个SortedList类型的字段:m_BeforeHandles和m_AfterHandles。它们负责存放方法名与BeforeAOPHandle和AfterAOPHandle对象之间的映射。添加这些映射的职责由以下两个方法完成:
protected virtual void AddBeforeAOPHandle(string methodName, BeforeAOPHandle beforeHandle)
{
lock (this.m_BeforeHandles)
{
if (!m_BeforeHandles.Contains(methodName))
{
m_BeforeHandles.Add(methodName, beforeHandle);
}
}
}
protected virtual void AddAfterAOPHandle(string methodName, AfterAOPHandle afterHandle)
{
lock (this.m_AfterHandles)
{
if (!m_AfterHandles.Contains(methodName))
{
m_AfterHandles.Add(methodName, afterHandle);
}
}
}
考虑到咱们要截取的方法可能会有多个,所以在类AOPSink中,又定义了两个抽象方法,负责添加全部的映射关系:
protected abstract void AddAllBeforeAOPHandles();
protected abstract void AddAllAfterAOPHandles();
而后在构造函数中,咱们初始化两个SortedList对象,并调用上述的两个抽象方法:
public AOPSink(IMessageSink nextSink)
{
m_NextSink = nextSink;
m_BeforeHandles = new SortedList();
m_AfterHandles = new SortedList();
AddAllBeforeAOPHandles();
AddAllAfterAOPHandles();
}
为了可以根据方法名得到相对应的委托对象,咱们又定义了两个Find方法。考虑到可能会有多个用户同时调用,在这两个方法中,我利用lock避免了对象的争用:
protected BeforeAOPHandle FindBeforeAOPHandle(string methodName)
{
BeforeAOPHandle beforeHandle;
lock (this.m_BeforeHandles)
{
beforeHandle = (BeforeAOPHandle)m_BeforeHandles[methodName];
}
return beforeHandle;
}
protected AfterAOPHandle FindAfterAOPHandle(string methodName)
{
AfterAOPHandle afterHandle;
lock (this.m_AfterHandles)
{
afterHandle = (AfterAOPHandle)m_AfterHandles[methodName];
}
return afterHandle;
}
接下来是IMessageSink接口要求实现的方法和属性:
public IMessageSink NextSink
{
get { return m_NextSink; }
}
public IMessage SyncProcessMessage(IMessage msg)
{
IMethodCallMessage call = msg as IMethodCallMessage;
string methodName = call.MethodName.ToUpper();
BeforeAOPHandle beforeHandle = FindBeforeAOPHandle(methodName);
if (beforeHandle != null)
{
beforeHandle(call);
}
IMessage retMsg = m_NextSink.SyncProcessMessage(msg);
IMethodReturnMessage replyMsg = retMsg as IMethodReturnMessage;
AfterAOPHandle afterHandle = FindAfterAOPHandle(methodName);
if (afterHandle != null)
{
afterHandle(replyMsg);
}
return retMsg;
}
public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
{
return null;
}
须要注意的是SyncProcessMessage()方法。在该方法中,经过FindBeforeAOPHandle()和FindAfterAOPHandle()方法,找到BeforeAOPHandle和AfterAOPHandle委托对象,并执行它们。即执行这两个委托对象具体指向的方法,相似与AspectJ中的before和after的execution。
如今,咱们就能够象AspectJ那样定义本身的aspect了。如权限管理一例,咱们定义一个类AuthorizationAOPSink,它继承了AOPSink:
public class AuthorizationAOPSink : AOPSink
{
public AuthorizationAOPSink(IMessageSink nextSink)
: base(nextSink)
{
}
}
而后在这个方法中,实现before和after的逻辑。注意before和after方法应与以前定义的委托BeforeAOPHandle和AfterAOPHandle一致。不过,以本例而言,并不须要实现after逻辑:
private void Before_Authorization(IMethodCallMessage callMsg)
{
if (callMsg == null)
{
return;
}
if (!permissions.Verify(Permission.ADMIN))
{
throw UnauthorizedException();
}
}
而后咱们override基类中的抽象方法AddAllBeforeAOPHandles()和AddAllAfterAOPHandles():
protected override void AddAllBeforeAOPHandles()
{
AddBeforeAOPHandle("ADDORDER", new BeforeAOPHandle(Before_Authorization));
AddBeforeAOPHandle("DELETEORDER", new BeforeAOPHandle(Before_Authorization));
}
protected override void AddAllAfterAOPHandles()
{
}
由于after逻辑不须要实现,所以重写AddAllAfterAOPHandles()时,使其为空就能够了(必须重写,由于该方法为抽象方法)。在AOPProperty类中,须要返回IMessageSink对象,因此还应修改原来的AOPProperty类中的GetObjectSink方法:
public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
{
return new AOPSink(nextSink);
return new AuthorizationAOPSink(nextSink);
}
比较一下上述的实现方案,自定义的继承AOPSink类的AuthorizationAOPSink就至关于AspectJ中的aspect。而与BeforeAOPHandle和AfterAOPHandle委托对应的方法,则至关于AspectJ的before和after语法。AddAllBeforeAOPHandles()和AddAllAfterAOPHandle()则至关于AspectJ的pointcut。经过引入委托的方法,使得咱们的AOP实现,具备了AspectJ的一些特性,而这些实现是不须要专门的编译器的。
很明显,若是咱们要求OrderManager类中新增的UpdateOrder方法,也要加入权限控制,那么咱们能够在AddAllBeforeAOPHandles()方法中,增长UpdaeOrder方法与before逻辑的映射:
AddBeforeAOPHandle("UPDATEORDER", Before_Authorization);
一样的,若是要对权限控制进行修改,开发业务经理对订单管理的权限,那么也只须要修改Before_Authorization()方法:
private void Before_Authorization(IMessage callMsg)
{
IMethodCallMessage call = callMsg as IMethodCallMessage;
if (call == null)
{
return;
}
if (!(permissions.Verify(Permission.ADMIN)|| permissions.Verify(Permission.MANAGER)))
{
throw UnauthorizedException();
}
}
4、进一步完善
因为咱们的委托列表m_BeforeHandles和m_AfterHandles为SortedList类型,所以做为key的methodName必须是惟一的。若是系统要求添加其余权限控制的逻辑,例如增长认证功能,就不能再在AuthorizationAOPSink类的AddAllBeforeAOPHandles()方法中增长方法名与认证功能的before逻辑之间的映射了。
private void Before_Authentication(IMessage callMsg){……}
protected override void AddAllBeforeAOPHandles()
{
……
AddBeforeAOPHandle("ADDORDER", new BeforeAOPHandle(Before_ Authentication));
AddBeforeAOPHandle("DELETEORDER", new BeforeAOPHandle(Before_ Authentication));
}
若是在AuthorizationAOPSink类中添加上面的代码,因为新增的“ADDORDER”key与前面重复,故执行程序时,是找不到相应的委托Before_Authentication的。
解决的办法就是为认证功能新定义一个aspect。因为在本方案中,实现AOP功能的不只仅是实现了IMessageSink接口的AOPSink类,同时该类还与Property、Attribute有关。也就是说,若是咱们新定义一个AuthenticationAOPSink,那么还要定义与之对应的AuthenticationAOPProperty类。为便于扩展,我采用了Template Method模式,为全部的property定义了抽象类AOPProperty,其中的抽象方法或虚方法,则留待其子类来实现。
public abstract class AOPProperty : IContextProperty, IContributeObjectSink
{
protected abstract IMessageSink CreateSink(IMessageSink nextSink);
protected virtual string GetName()
{
return "AOP";
}
protected virtual void FreezeImpl(Context newContext)
{
return;
}
protected virtual bool CheckNewContext(Context newCtx)
{
return true;
}
#region IContributeObjectSink Members
public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink nextSink)
{
return CreateSink(nextSink);
}
#endregion
#region IContextProperty Members
public void Freeze(Context newContext)
{
FreezeImpl(newContext);
}
public bool IsNewContextOK(Context newCtx)
{
return CheckNewContext(newCtx);
}
public string Name
{
get { return GetName(); }
}
#endregion
}
与原来的AOPProperty类相比,IContextProperty,IContributeObjectSink接口的方法与属性,都没有直接实现,而是在其内部调用了相关的抽象方法和虚方法。包括:抽象方法CreateSink(),虚方法FreezeImpl(),CheckNewContext()以及GetName()。对于其子类而言,须要override的,主要是抽象方法CreateSink()和GetName()(由于Property的Name必须是惟一的),至于其余虚方法,能够根据须要选择是否override。例如,自定义权限控制的属性类AuthorizationAOPProperty:
public class AuthorizationAOPProperty :AOPProperty
{
protected override IMessageSink CreateSink(IMessageSink nextSink)
{
return new AuthorizationAOPSink(nextSink);
}
protected override string GetName()
{
return "AuthorizationAOP";
}
}
在该类中,咱们override了CreateSink()方法,建立了一个AuthorizationAOPSink对象。同时override了虚方法GetName,返回了本身的一个名字“AuthorizationAOP”。
关于Attribute类,观察其方法GetPropertiesForNewContext(),其实现是在IConstructionCallMessage消息的上下文property中添加自定义property。这些property组成了一个链,它是能够静态添加的。鉴于此,咱们能够采起两种策略:
一、 全部的aspect都使用同一个Attribute。其实现以下:
[AttributeUsage(AttributeTargets.Class)]
public class AOPAttribute:ContextAttribute
{
public AOPAttribute()
: base("AOP")
{
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
ctorMsg.ContextProperties.Add(new AuthorizationAOPProperty());
ctorMsg.ContextProperties.Add(new AuthenticationAOPProperty());
}
}
在方法GetPropertiesForNewContext()中,添加多个自定义Property。在添加Property时,须要注意添加Property的顺序。
二、 不一样的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,因此,第二个方案更佳。
5、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();
}
}
}
运行结果以下:
6、结论
在.Net平台下采用动态代理技术实现AOP,其原理并不复杂,而.Net Framework也提供了足够的技术来实现它。若是再结合好的设计模式,提供一个基本的AOP框架,将大大地简化开发人员处理“aspect”的工做。固然,本文虽然提供了实现AOP的实例,但其架构的设计还远远不能达到企业级的要求,如在稳定性、可扩展性上还需通过进一步的测试与改善。例如咱们能够经过配置文件的形式,来配置方法与方面之间的映射。同时,因为采用了动态代理,在性能上还期待改进。
使用动态代理技术实现AOP,对实现AOP的类有一个限制,就是必须派生于ContextBoundObject类,这对于单继承语言来讲,确实是一个比较致命的缺陷。所谓“仁者见仁,智者见智”,这就须要根据项目的状况,作出正确的抉择了。