在.Net中关于AOP的实现(二)

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值