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的顺序。