RogerTong's Tech Space

文章书傲骨,程序写春秋

导航

Castle AOP 系列(一):对类方法调用的拦截

Posted on 2008-07-09 16:42  RogerTong  阅读(3870)  评论(3编辑  收藏  举报

熟悉Castle的朋友一定清楚:在Castle体系中,有一个叫Aspect#的子项目。Aspect#是一个AOP的框架,在这篇文章中,我并不打算直接开始讲Aspect#,因为Aspect#的封装过于完善,不太利于用来讲述AOP的具体实现细节。其实Aspect#的基础是DynamicProxy,所以,我们先来讲讲DynamicProxy。

在很多朋友的眼中,AOP似乎是一个很神秘的东西,其实在我看来,AOP的本质就是对一切操作行为的拦截,在.Net中,AOP的本质更简单,纯粹是对方法的拦截。为什么这么说呢?因为在.Net中,一切的操作都是方法调用:事件的 “+=” 及 “-=”最终被转换为 Addxxxx(...),Removexxxxx(...)类型的方法;属性的 get/set 过程也被转换为 getxxxxxx(...),setxxxxxx(...)类型的方法;而方法的本身就更不用说了。


方法拦载的实现的原理是动态构建类型,动态构建类型的功能是由“mscorlib.dll” 这个.Net核心的程序集提供的,有兴趣的朋友可以详细研究一下这个程序集的“System.Reflection.Emit”命名空间的内容。由于方法的拦载是动态构建类型,所以我们在拦截类方法时,可以采取用动态构造类的方式,从该类继承一个子类,重载并改写类中需要拦截的方法。因此,我们不难理解,为什么在Castle 的 AOP中实现对类方法的拦截,都需要该类中的可被拦载的方法都是能够被子类重载的(override)。

说了这么多,让我们来写一个简单的程序来演示在 Castle 中AOP 的基础吧,先看看一个简单的类型:


 

Person的代码
  1. using System;   
  2.   
  3. namespace Unit6   
  4. {   
  5.     public class Person   
  6.     {   
  7.         public virtual void SayHello()   
  8.         {   
  9.             Console.WriteLine("Hello!");   
  10.         }   
  11.   
  12.         public virtual void SayName()   
  13.         {   
  14.             Console.WriteLine("My Name is Roger");   
  15.         }   
  16.   
  17.         public void SayOther()   
  18.         {   
  19.             Console.WriteLine("Yes,I do!");   
  20.         }   
  21.     }   
  22. }  

 


这个类型没什么好说的,只是输出一些字符串而以。惟一需要注意的是:前两个方法都是虚方法,而“SayOther”不是虚方法,即是说“SayOther”不可以用一般的方式重载


再来看看方法拦载器的代码:


 

拦载器的代码
  1. using System;   
  2. using Castle.DynamicProxy;   
  3.   
  4. namespace Unit6   
  5. {   
  6.     public class SimpleInterceptor : StandardInterceptor   
  7.     {   
  8.         protected override void PreProceed(   
  9.             IInvocation invocation, params object[] args)   
  10.         {   
  11.             Console.WriteLine("Simple Interceptor Running! Method Name:{0}."  
  12.                 , invocation.Method.Name);   
  13.             base.PreProceed(invocation, args);   
  14.         }   
  15.     }   
  16. }  

 


Castle DynamicProxy提供了一个标准的方法拦截器,在一般的情况下,从这个标准的拦截器继承便可以完成大部分方法拦载上面的需求。StandardInterceptor中提供了三个可重载的方法:

  1. PreProcced,在进入拦截的方法之前调用。
  2. PostProcced,在拦截的方法运行完成后调用。
  3. Intercept,在拦截的方法返回时调用


正如上面的代码所展示的,我们会在被拦载的方法调用之前,输出相关的一些信息,接下来我们来看看如何使用这个写好的拦截器


 

C#代码
  1. using System;   
  2. using Castle.DynamicProxy;   
  3.   
  4. namespace Unit6   
  5. {   
  6.     internal class Program   
  7.     {   
  8.         private static void Main()   
  9.         {   
  10.             SimpleInterceptor interceptor = new SimpleInterceptor();   
  11.             ProxyGenerator generator = new ProxyGenerator();   
  12.             Person person = (Person) generator.   
  13.                 CreateClassProxy(typeof (Person), interceptor);   
  14.   
  15.   
  16.             Console.WriteLine("Current Type:{0},Base Type:{1}",    
  17.                 person.GetType(), person.GetType().BaseType);   
  18.             Console.WriteLine();   
  19.   
  20.                
  21.             person.SayHello();   
  22.             Console.WriteLine();   
  23.   
  24.             person.SayName();   
  25.             Console.WriteLine();   
  26.   
  27.             person.SayOther();   
  28.   
  29.             Console.ReadLine();   
  30.         }   
  31.     }   
  32. }  

 


在上面的代码中,ProxyGenerator其实是一个动态的类型构造器,它依据Person类型,并加入相应的拦载器构造出了一个新的类型,我们来查看一下运行输出:


根据输出的第一行,我们可以知道,ProxyGenerator构造了一个新的类型,这个类型继承自Person,由于这个类型的SayOther方法不可以被子类重载,所以这个方法无法被拦截。

点击下载程序源文件