您的位置:首页 > 其它

[转]基于Dynamic Proxy技术的方法拦截器开发

2010-04-20 16:22 344 查看
  来自<<msdn开发精选>>代理技术--代码变得更简洁

  在面向对象编程中,会用到大量的类,并且会多次调用类中的方法。有时可能需要对这些方法的调用进行一些控制。如在权限管理中,一些用户没有执行某些方法的权限。又如在日志系统中,在某个方法执行完后,将其执行的结果记录在日志中。处理这些需求的一般做法是在调用这些方法的地方加上适当的代码。如以下C#代码如示:

public class Class1
{
public void MyMethod()
{
...
}
static void Main()
{
Class1 c1 = new Class1();
if(permit())
{
c1.MyMethod();
logger();
}
}
}


  在以上代码中,permit()是一个得到MyMethod方法执行权限的函数,如果MyMethod方法可以被执行,那么permit()返回true,否则,返回false。logger()是记录日志的函数。

  我们可以看出,在这段程序中存在一个问题,就是它的主要功能是执行MyMethod方法,至于权限控制以及日志功能只是它的次要功能(这里说它们是次要功能,并不是说它们不重要,而是说没有这些功能并不影响程序的核心功能的执行)。而将这些次要功能和程序的主要业务逻辑混在一起,如果程序所涉及的类比较多的话,这些次要功能的代码将和业务逻辑代码紧密地结合在一起,这样在修改某一部分时(比如换一个写日志的函数),必须要修改大量的代码。而且程序员在考虑业务逻辑的同时,还要关注这些次要功能,从而无法将精力集中在业务逻辑上。

  根据以上在软件开发中存在的不足,人们提出了代理(Proxy)技术用以解决上述的问题。代理技术的基本原理是在待调用类和调用者之间加了一个代理类(Proxy Class),这个代理类有两个作用。第一个作用是执行被代理类的方法。第二个作用是在代理类中可以加入控制这个方法的代码,从而使调用者不必关心和自己的业务无关的事情。现将上例用代理技术重新实现,代码如下:

代码

public Object Wrap(Type type)
{
Type newType = null;
try
{
m_Type = type;
GenerateType();
GenerateDelegateClass();
GenerateFields();
GenerateCallBackMethods();
GenerateOverrideMethods();
GenerateConstructor();
newType = m_TypeBuilder.CreateType(); //建立代理类的Type
//建立Nested Class的Type
foreach (TypeBuilder tb in m_NestedTypeBuilders)
tb.CreateType();
m_Assembly.Save("DynamicProxy.dll"); //保存这个代理类为DynamicProxy.dll
}
catch (Exception err)
{
throw err;
}
//建立代理类实例
return Activator.CreateInstance(newType, new Interceptor());
}


  在这个方法中,有一个地方需要注意,在建立一个Nested Class之前,应先建立包含这个Nested Class的类,然后再建立Nested Class。在建完代理类后,将其保存在DynamicProxy.dll中(如果你感兴趣,可以用Microsoft的ildasm.exe查看这个dll的IL。)。最后建立了代理类的实例,将Interceptor的一个实例通过参数传入到代理类的构造函数中。

如何应用动态代理技术
  至此所有的工作都完成了。我们可以将以上代码放入一个叫DynamicProxyBuilder的类中。以下代码是如何使用DynamicProxyBuilder的一个例子:

  DynamicProxyBuilder dynamicProxyBuilder = new DynamicProxyBuilder();
  Class1 class1 = (Class1)dynamicProxyBuilder.Wrap(typeof(Class1));
  class1.MyMethod();

  以上代码可以为Class1生成一个代理类,如果用户想控制这个方法,可以在Call方法中加入适当的代码即可。在使用DynamicProxyBuilder时需要注意两点:
  1、被代理类的public方法必须都是virtual的,否则无法继承。
  2、在建立一个类时必须用Wrap,而不能直接用new关键字。

总结
  Dynamic Proxy技术也是AOP(Aspect Oriented Programming)技术的核心。通过动态代理实现的AOP,一般可分为两个部分。第一部分是动态代理的实现,在这部分不同的语言在实现上有很大的不同。由于C#没有提供象java那样的动态代理机制,因此这些工作必须由我们自己来做,以上所述便是用C#实现动态代理的全部过程。第二部分就是利用这个动态代理机制来控制方法的执行。由上述可知,在这个方法拦截器中有一个用于改变方法调用轨迹的类Interceptor,当调用被代理类方法时,先调用这个类中的Call方法,然后在Call方法中加入适当代码来决定是否执行这个被代理类的方法。我们可以更进一步地去想,如果在Call方法中加入一些和AOP相关的代码,例如在满足一定条件下,在方法执行之前或执行之后插入一些代码,或者干脆不让这个方法执行。这样就成为一个真正的AOP framework了。
  AOP是动态代理的最具代表性的应用。它在程序设计中的应用十分广泛。在一般的系统中,可分为两个部分,核心功能和系统功能。所谓核心功能就是和这个系统相关的业务功能,如在mail服务器中的核心功能是接收和发送电子邮件。系统功能则可以看成是系统的可选功能,如日志、安全等。如果没有了这些功能,mail服务器仍可以照常工作,只是不太安全了,并且无法查找以往的记录。实现这些系统功能,一般的作法是将系统功能的代码和核心功能的代码混在一起。这样做不仅加大了系统设计和实现的难度,而且使设计系统核心功能的程序必须要考虑这些系统的功能,分散了他们的注意力。然而,利用AOP却可解决以上问题,从而达到分离核心功能和系统功能的目的。
  除了AOP,动态代理还有许多其它的用途。比如我们要开发一个远程服务的程序。在客户端要执行服务端的一些方法。一般的作法是利用.net remoting或直接用socket进行通讯,告诉服务器要调用的方法,然后服务器调用方法后通过.net remoting或socket将执行结果返回。这样做从表面上看没什么问题。但是对于某些方法的调用,并不要求结果的实时变化,也就是说当服务器上的数据变化了,并不要求通过这个方法得到的数据马上变化,可以有一段时间的延迟。如果是这样的话,那么每次都让服务器重新执行这个方法好象有点得不偿失。由此我们自然想到了Cache(缓存)。当要被缓存的方法在第一次调用后,将其结果存入Cache。当以后再调用这个方法时,可以直接从Cache中取结果,而无需每次都执行这个方法。但这样还有一个问题,如果我们无法修改这个服务器的代码,那么如何加入有关Cache的代码呢?即使能修改代码,那么我们是否能当不需要这个Cache时很容易地将其关闭呢?如果这个服务器使用了动态代理或者直接使用了利用动态代理技术实现的AOP,这么这些问题简直就是小菜一碟。即使你不了解服务器的源代码甚至是没有源代码,你仍可以利用方法拦截来实现这个Cache功能。
  当然,动态代理除了上述的应用外,还可用在其它许多地方。如果你充分发挥自己的想象力,利用这种技术还可以做出许多应用非常广泛的程序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: