关注开源代码的实际应用
java中有动态代理的概念,DotNet中没有,castle的DynamicProxy就是提供了类似于java动态代理的功能。动态代理是很多现代软件技术的基础,例如AOP,现在有很多项目中采用了castle的DynamicProxy,他们包括:NHibernate (http://nhibernate.sourceforge.net/)、Retina.Net http://www.gotdotnet.com/workspaces/workspace.aspx?id=fd081831-5a33-45cd-9f23-a828dd1f3fd1)、iBatis.Net (http://www.sf.net/projects/ibatisnet)、Aspect# (http://aspectsharp.sf.net)、RhinoMocks (http://www.ayende.com/projects/rhino-mocks.aspx)
这里介绍一下DynamicProxy的简单使用和基本原理。一个使用DynamicProxy的简单的例子:
- using System;
- using Castle.DynamicProxy;
- namespace DynamicProxy
- {
- class DynamicProxyTest
- {
- public static void Main()
- {
- ProxyGenerator generator = new ProxyGenerator();
- object proxy = generator.CreateClassProxy(typeof(RealClass), new MyProxyInterceptor());
- RealClass a = (proxy as RealClass);
- a.DoSomething();
- Console.WriteLine("");
- a.DoB();
- Console.WriteLine("");
- a.DoC();
- Console.ReadLine();
- }
- }
- public class RealClass
- {
- public RealClass() { }
- public virtual void DoSomething()
- {
- Console.WriteLine("DoSomething() in RealClass在运行。");
- }
- public virtual void DoB()
- {
- Console.WriteLine("DoB() in RealClass在运行。");
- }
- public void DoC()
- {
- Console.WriteLine("DoC() in RealClass在运行。");
- }
- }
- public class MyProxyInterceptor : StandardInterceptor
- {
- protected override void PreProceed(IInvocation invocation, params object[] args)
- {
- System.Console.WriteLine("PreProceed:" + invocation.Method.Name);
- base.PreProceed(invocation, args);
- }
- protected override void PostProceed(IInvocation invocation, ref object returnValue, params object[] arguments)
- {
- if (invocation.Method.Name == "DoB")
- {
- Console.Out.WriteLine("PostProceed---DoB in ProxyInterceptor-- 在运行");
- }
- else
- {
- System.Console.WriteLine("PostProceed--{0} 在运行", invocation.Method.Name);
- }
- base.PostProceed(invocation, ref returnValue, arguments);
- }
- }
- }
运行结果:
PreProceed:DoSomething
DoSomething() in RealClass在运行。
PostProceed--DoSomething 在运行
PreProceed:DoB
DoB() in RealClass在运行。
PostProceed---DoB in ProxyInterceptor-- 在运行
DoC() in RealClass在运行。
这个例子很简单,我们定义了一个需要动态代理的类RealClass,动态代理只要求该类需要代理的方法是虚方法。MyProxyInterceptor 是一个拦截器类,该类需要实现IInterceptor 接口,一般来说需要继承自StandardInterceptor类。通过查看StandardInterceptor源代码我们知道 StandardInterceptor是一个实现了模版方法模式的类。
- protected virtual void PreProceed(IInvocation invocation, params object[] args){}
- protected virtual void PostProceed(IInvocation invocation, ref object returnValue, params object[] args){}
- public virtual object Intercept(IInvocation invocation, params object[] args)
- {
- PreProceed(invocation, args);
- object retValue = invocation.Proceed( args );
- PostProceed(invocation, ref retValue, args);
- return retValue;
- }
我们的具体拦截器类通过重载PreProceed(IInvocation invocation, params object[] args)和protected virtual void PostProceed(IInvocation invocation, ref object returnValue, params object[] args)方法,将我们需要在被代理方法执行之前和之后要添加的操作插入到方法执行过程中。其中IInvocation 封装了要代理的方法,returnValue是被代理方法可能存在的返回值,args是参数数组。我们的拦截器很简单,比如PreProceed只是 System.Console.WriteLine("PreProceed:" + invocation.Method.Name);然后调用父类base.PreProceed(invocation, args);PostProceed添加了一点功能,只是判断被代理的方法名是不是DoB,如果是 Console.Out.WriteLine("PostProceed---DoB in ProxyInterceptor-- 在运行");否则System.Console.WriteLine("PostProceed--{0} 在运行", invocation.Method.Name);然后调用base.PostProceed(invocation, ref returnValue, arguments);
从运行结果我们可以看出,对于RealClass的DoSomething和DoB方法,都有拦截器的输出,就是我们在MyProxyInterceptor中定义的。但DoC方法没有被代理,原因是DoC不是virtual方法。
最后看一下使用。
- ProxyGenerator generator = new ProxyGenerator();//ProxyGenerator 用于生成代理对象
- object proxy = generator.CreateClassProxy(typeof(RealClass), new MyProxyInterceptor());
- //通过generator.CreateClassProxy方法动态生成代理类。
- RealClass a = (proxy as RealClass);//生成的代理对象是RealClass 的子类,所以可以强制转换为RealClass
- a.DoSomething();//调用代理实例的相应与被代理的相同的方法,如果该方法已经被代理,则执行代理后的方法。
- Console.WriteLine("");
- a.DoB();
- Console.WriteLine("");
- a.DoC();//如果该方法没有被代理,则执行代理前的方法。
- Console.ReadLine();
通过generator.CreateClassProxy方法动态生成代理类将会把我们指定给要代理的类或接口的被代理方法封装入IInvocation 对象。并通过Intercept方法插入我们定义的PreProceed(invocation, args);和PostProceed(invocation, ref retValue, args);这些动态生成的类会直接按IL格式写入到动态代理类中,这样动态生成的动态代理类中就有类似下面的代码:
- public CProxyTypeRealClass0(IInterceptor interceptor1)
- {
- this.__interceptor = interceptor1;
- }
- public override void DoSomething()
- {
- IInvocation local0;
- object local1;
- object[] local2;
- local0 = new SameClassInvocation(callable1, this, info1);//SameClassInvocation实现了IInvocation
- local2 = new Object[0];
- local1 = this.__interceptor.Intercept(local0, local2);//.__interceptor是我们定义的MyProxyInterceptor
- }
其中SameClassInvocation继承自AbstractInvocation实现了IInvocation,其中的proceed方法如下:
- public virtual object Proceed(params object[] args)
- {
- // If the user changed the target, we use reflection
- // otherwise the delegate will be used.
- if (changed_target == null)
- {
- return callable.Call( args );//callabel是动态生成的,封装了被代理的方法。
- }
- else
- {
- return Method.Invoke( changed_target, args );
- }
- }
简单的说就是,通过ProxyGenerator生成类的代理后,所产生的代理类就是CProxyTypeRealClass0,当调用 DoSomething方法时,就将我们在MyProxyInterceptor定义的方法插入到被代理对象方法DoSomething的执行前后,从而实现了对方法的动态代理。当然这种代理职能对方法执行前后进行拦截,要实现根复杂的拦截,需要AOP。