赴美生子 月子中心 美宝论坛

Castle 动态代理介绍

 介绍

        CLR提供的代理功能非常棒。ProxyAttributemessage sinks等奇妙的想法,使对平台进行扩展非常容易。

       不过,这里还是有些缺点,例如:如果要使用代理功能,你的类必须继承自MarshalByRef or ContextBoundObject (该类型被另外的环境所支持),通过这样做,你扰乱了类的对象模型层次,这是一种高侵入。不过,如果你需要自己来控制对象模型,那么这种方式是可选的,

         这篇文章说明了怎么使用Castle Project中的动态代理,使用一个快速、干净的方式为你的类建立一个拦截器(interceptors),如动态代理一样高效,不会使用反射机制去调用一个对象实例的方法。

怎么使用

        动态代理能代理接口和实现类,你总是需要提供被代理对象的类型和拦截器的实例,拦截器将会在对代理的每次方法调用的时候被调用,所以你可以在拦截器逻辑中承载一些逻辑(日志、事务等)和然后决定是否继续处理该调用,如果需要继续处理,你必须调用Proceed方法。

 1 public class MyInterceptor : IInterceptor
 2 
 3 {
 4     public object Intercept(IInvocation invocation, params object[] args)
 5     {
 6         DoSomeWorkBefore(invocation, args);
 7  
 8         object retValue = invocation.Proceed( args );
 9  
10         DoSomeWorkAfter(invocation, retValue, args);
11  
12         return retValue;
13     }
14 }
15 


        IInvocation接口向你提供了一系列有用的信息:

 1 public interface IInvocation
 2 {
 3     object Proxy { get; }
 4  
 5     object InvocationTarget { getset; }
 6  
 7     MethodInfo Method { get; }
 8  
 9     object Proceed( params object[] args );
10 }
11 

      为了实现接口,你必须标识出目标对象实例,复杂么?其实不然,考虑下面一个例子:

 1 public interface IMyInterface
 2 {
 3     int Calc(int x, int y);
 4     int Calc(int x, int y, int z, Single k);
 5 }
 6  
 7 public class MyInterfaceImpl : IMyInterface
 8 {
 9     public virtual int Calc(int x, int y)
10     {
11         return x + y;
12     }
13  
14     public virtual int Calc(int x, int y, int z, Single k)
15     {
16         return x + y + z + (int)k;
17     }
18 }
19  
20 ProxyGenerator generator = new ProxyGenerator();
21  
22 IMyInterface proxy = (IMyInterface) generator.CreateProxy( 
23     typeof(IMyInterface), new StandardInterceptor(), new MyInterfaceImpl() );
24 

        这个就是作为DynamicProxy的需求,需要一个针对调用的默认目标

        后面我们将解释为什么。

       现在,如果你需要代理一个真实类,这个类不能是sealed,而且只有virtual方法才能被拦截,理由是动态代理将为该类建立一个子类,该子类将重载所有方法,所以能把调用放到拦截器中。看下面一个例子:

 1 ProxyGenerator generator = new ProxyGenerator();
 2  
 3 Hashtable proxy = (Hashtable) generator.CreateClassProxy( 
 4     typeof(Hashtable), new HashtableInterceptor() );
 5  
 6 object value = proxy["key"]; // == "default"
 7  
 8 public class HashtableInterceptor : StandardInterceptor
 9 {
10     public override object Intercept(IInvocation invocation, params object[] args)
11     {
12         if (invocation.Method.Name.Equals("get_Item"))
13         {
14             object item = base.Intercept(invocation, args);
15             return (item == null? "default" : item;
16         }
17         return base.Intercept(invocation, args);
18     }
19 }
20 



 

如果你不希望代理的类暴露出一个默认的构造函数,OK,你只需要提供一些参数给CreateClassProxy

    Mixins

      Mixins是一种在C++世界很著名的继承,Mixin样式的继承,能将一个类和其他的类进行混合,同时暴露出单独的能力,动态代理允许你一个类和其他的类进行混合,结果将生成一个混合的代理实例,如果混合类暴露接口,他们将自动通过代理实例进行暴露。

 1 public interface ISimpleMixin
 2 {
 3     int DoSomething();
 4 }
 5  
 6 public class SimpleMixin : ISimpleMixin
 7 {
 8     public int DoSomething()
 9     {
10         return 1;
11     }
12 }
13  
14 ProxyGenerator generator = new ProxyGenerator();
15 GeneratorContext context = new GeneratorContext();
16  
17 SimpleMixin mixin_instance = new SimpleMixin();
18  
19 context.AddMixinInstance( mixin_instance );
20  
21 SimpleClass proxy = (SimpleClass) generator.CreateCustomClassProxy( 
22     typeof(SimpleClass), interceptor, context );
23  
24 ISimpleMixin mixin = (ISimpleMixin) proxy;
25 


 

   象Ruby一样的动态语言是mixins的天堂,每种混合的模块通过目标类暴露,但是那是另一个讨论的主题。
   Aspect#使mixins更上了一个台阶,他实现了一个协议,允许mixins实例得到代理实例的引用,然而动态代理将这种决定带给了开发人员。

 

内部实现

       动态代理生成了一个类,类似如下代码

 1 public class ProxyGenerated : YourClass
 2 {
 3   // Exposes all constructors
 4   
 5   // Overrides all methods
 6   
 7   public override int DoSomething(int x)
 8   {
 9     MethodInfo m = ldtoken currentMethod;
10     IInvocation invocation = ObtainInvocationFor( deletegateForDoSomething, 
11                              callableForDoSomething, m);
12     return (int) _interceptor.Intercept( invocation, x );
13   }
14  
15   private int BaseCallDoSomething(int x)
16   {
17     return base.DoSomething(x);
18   }
19 }
20 


 

         正如你所见到的,动态代理依靠委托达到很好的性能,唯一的性能瓶井是在对值类型进行装箱和拆箱工作上。

         基本上,每个代理都有一个指针指向调用基类方法的另外一个方法,他会在你使用IInvocation实例上的Proceed时发生。

 

结论

    对于程序集的静态织入,可以考虑RAIL项目,如果你需要的是动态,则考虑动态代理。同时,我也需要谢谢所有的回馈和从Aspect#Castle开发邮件列表中收到的补丁,动态代理的用户给了我一次又一次重构的力量。
关于动态代理的更新信息,请检查其站点




文章出处:http://www.codeproject.com/csharp/hamiltondynamicproxy.asp

posted @ 2005-12-04 22:01  SuperBowl  阅读(1804)  评论(0编辑  收藏  举报