一、AOP实现初步

AOP将软件系统分为两个部分:核心关注点和横切关注点。核心关注点更多的是Domain Logic,关注的是系统核心的业务;而横切关注点虽与核心的业务实现无关,但它却是一种更Common的业务,各个关注点离散地分布于核心业务的多处。这意味着,如果不应用AOP,那么这些横切关注点所代表的业务代码,就会分散在系统各处,导致系统中的每个模块都与这些业务具有很强的依赖性。在这里,所谓横切关注点所代表的业务,即为“方面(Aspect)”,常见的包括权限控制、日志管理、事务处理等等。

以权限控制为例,假设一个电子商务系统,需要对订单管理用户进行权限判定,只有系统用户才能添加、修改和删除订单,那么传统的设计方法是:

public class OrderManager

{

private ArrayList m_Orders;

public OrderManager()

{

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()等有关权限的代码,解除了订单管理与权限管理之间的耦合。

二、与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特性。

三、.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();

}

}

四、进一步完善

由于我们的委托列表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组成了一个链,它是可以静态添加的。鉴于此,我们可以采取两种策略:

1、 所有的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的顺序。

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类,这对于单继承语言来说,确实是一个比较致命的缺陷。所谓“仁者见仁,智者见智”,这就需要根据项目的情况,做出正确的抉择了。

.NET AOP的实现的更多相关文章

  1. 基于spring注解AOP的异常处理

    一.前言 项目刚刚开发的时候,并没有做好充足的准备.开发到一定程度的时候才会想到还有一些问题没有解决.就比如今天我要说的一个问题:异常的处理.写程序的时候一般都会通过try...catch...fin ...

  2. Spring基于AOP的事务管理

                                  Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...

  3. 学习AOP之透过Spring的Ioc理解Advisor

    花了几天时间来学习Spring,突然明白一个问题,就是看书不能让人理解Spring,一方面要结合使用场景,另一方面要阅读源代码,这种方式理解起来事半功倍.那看书有什么用呢?主要还是扩展视野,毕竟书是别 ...

  4. 学习AOP之深入一点Spring Aop

    上一篇<学习AOP之认识一下SpringAOP>中大体的了解了代理.动态代理及SpringAop的知识.因为写的篇幅长了点所以还是再写一篇吧.接下来开始深入一点Spring aop的一些实 ...

  5. 学习AOP之认识一下Spring AOP

    心碎之事 要说知道AOP这个词倒是很久很久以前了,但是直到今天我也不敢说非常的理解它,其中的各种概念即抽象又太拗口. 在几次面试中都被问及AOP,但是真的没有答上来,或者都在面上,这给面试官的感觉就是 ...

  6. .Net中的AOP系列之构建一个汽车租赁应用

    返回<.Net中的AOP>系列学习总目录 本篇目录 开始一个新项目 没有AOP的生活 变更的代价 使用AOP重构 本系列的源码本人已托管于Coding上:点击查看. 本系列的实验环境:VS ...

  7. .NET里简易实现AOP

    .NET里简易实现AOP 前言 在MVC的过滤器章节中对于过滤器的使用就是AOP的一个实现了吧,时常在工作学习中遇到AOP对于它的运用可以说是很熟练了,就是没想过如果自己来实现的话是怎么实现的,性子比 ...

  8. 在.Net中实现自己的简易AOP

    RealProxy基本代理类 RealProxy类提供代理的基本功能.这个类中有一个GetTransparentProxy方法,此方法返回当前代理实例的透明代理.这是我们AOP实现的主要依赖. 新建一 ...

  9. 使用Java原生代理实现AOP

    ### 本文由博主柒.原创,转载请注明出处 ### 完整源码下载地址 [https://github.com/MatrixSeven/JavaAOP](https://github.com/Matri ...

  10. 【开源】.Net Aop(静态织入)框架 BSF.Aop

    BSF.Aop .Net 免费开源,静态Aop织入(直接修改IL中间语言)框架,类似PostSharp(收费): 实现前后Aop切面和INotifyPropertyChanged注入方式. 开源地址: ...

随机推荐

  1. poj2709 贪心基础

    D - 贪心 基础 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:65536KB     64bi ...

  2. 如何在WebSocket类中访问Session

    我最近正在做一个基于websocket的webQQ,最后代码会开源带github上,所以过程中我就不贴所有的代码啦~就贴问题的关键. 我在WebSocket里发消息的时候需要用到session,因为在 ...

  3. IE attachEvent事件处理程序(事件绑定的函数)的this指向的是window不是执行当前事件的dom元素

    IE attachEvent事件处理程序(事件绑定的函数)的this指向的是window不是执行当前事件的dom元素. attachEvent(type,listener); listener函数中的 ...

  4. web.config 拆分

    <appSettings configSource="xxx.config"> </appSettings> 在 web.config 加入上面  然后创建 ...

  5. 使用div+iframe实现弹窗及弹出内容无法显示的解决

    使用div+iframe实现弹窗 除了使用实际的弹出窗口,还可以使用控制一个div的display属性来模拟一个弹出窗口的操作,这里使用在Div里放一个iFrame的方式,主要考虑到可以在需要的时候加 ...

  6. python学习视频整理

    python3英文视频教程(全87集) http://pan.baidu.com/s/1dDnGBvV python从入门到精通视频(全60集)链接:http://pan.baidu.com/s/1e ...

  7. 手把手教你清除WIN7的C盘垃圾

    WIN7系统用着用着C盘会变得越来越大,可用空间变得越来越小,磁盘清理,和安全卫士怎么清也清不出这些系统深度的垃圾.我们可以手动删除,释放C盘空间. 这样一清理下来,结果我的C盘就释放了近10个GB的 ...

  8. 微软在MSDN中更新了Win8.1批量授权版镜像(中文版更新完毕&版本说明)

    微软在MSDN中更新了Win8.1大客户专业版和企业版镜像,零售版镜像(即专业版+核心版二合一镜像)没有更新,依然是9月份发布的版本.已证实,新的批量授权版镜像是集成了GA Rollup A更新,并且 ...

  9. android官方侧滑菜单DrawerLayout详解

    drawerLayout是Support Library包中实现了侧滑菜单效果的控件,可以说drawerLayout是因为第三方控件如MenuDrawer等的出现之后,google借鉴而出现的产物.d ...

  10. Speech Module

    Speech Module 1 FIRST_TEN = ["one", "two", "three", "four", ...