Spring系列(1)--创建动态代理类

来源:互联网 发布:软件园源码 编辑:程序博客网 时间:2024/05/16 10:24

象DotNet,Java之类的语言能够进行动态代理类的创建,得益于其本身并不是直接编译成机器代码,而是编译成中间语言,在运行时才解释或动态编译成目标机器语言。这也是为什么这些概念先在Java兴起的根本原因。产生动态代理类,一般都是利用Emit命名空间的指令,但这个对IL的要求比较高,我这里利用C#提供的动态编译功能实现,

优点是直观,容易理解,不用熟悉IL指令,缺点当然是显得不怎么专业。

(网上很多利用Emit,IL指令构建动态代理类的代码)

能够动态代理(我更倾向于用装饰),一个很关键的地方就是要求你的类中需要被监视(hook)的成员至少是保


护的虚方法.

下面就是动态代理类的工厂类,这里先介绍这个类,后面的博文会解释为什么要这么做:

//代理类工厂,简单的工厂方法.

 

 

[csharp] view plain copy print?
  1. public class MyProxyFactory  
  2.     {  
  3.   
  4.         object _target;  
  5.         private List<IMethodInterceptor> _adviceList = new List<IMethodInterceptor>();  
  6.   
  7.        //所谓的前置,后置等通知性类,其实就是要注入的间谍。  
  8.         public void Add(IMethodInterceptor advice)  
  9.         {  
  10.             _adviceList.Add(advice);  
  11.         }  
  12.   
  13.        //构造函数,传入目标对象.  
  14.         public MyProxyFactory(object target)  
  15.         {  
  16.             _target = target;  
  17.         }  
  18.   
  19.        // 创建并放回代理类。注意,这里是每次都创建,实际上是可以缓存的.  
  20.   
  21.         public object GetProxyClass()  
  22.         {  
  23.             StringBuilder theClassBuilder = new StringBuilder();  
  24.             Type theTargetType = _target.GetType();  
  25.             string theProxyClassName = "__" + theTargetType.Name + "_Proxy";  
  26.               
  27.             theClassBuilder.AppendLine("using System;");  
  28.             theClassBuilder.AppendLine("using System.Collections.Generic;");  
  29.             theClassBuilder.AppendLine("using System.Text;");  
  30.             theClassBuilder.AppendLine("using System.Reflection;");  
  31.             theClassBuilder.AppendLine("using System.Reflection.Emit;");  
  32.   
  33.             theClassBuilder.AppendLine("namespace " + theTargetType.Namespace);  
  34.             theClassBuilder.AppendLine("{");  
  35.             theClassBuilder.AppendLine("public class "+theProxyClassName+" : " + theTargetType.FullName + "{");  
  36.             theClassBuilder.AppendLine("   private " + theTargetType.FullName + " _target;");  
  37.             theClassBuilder.AppendLine("   private List<IMethodInterceptor> _adviceList = null;");  
  38.             theClassBuilder.AppendLine("   public __" + theTargetType.Name + "_Proxy(" + theTargetType.FullName + " target, List<IMethodInterceptor> AdviceList)");  
  39.             theClassBuilder.AppendLine("   {");  
  40.             theClassBuilder.AppendLine("   _target = target;");  
  41.             theClassBuilder.AppendLine("   this._adviceList = AdviceList;");  
  42.             theClassBuilder.AppendLine("   }");  
  43.             //获取目标类的方法,准备给代理类继承  
  44.             MethodInfo[] methodinfos = theTargetType.GetMethods(BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance);  
  45.             foreach (MethodInfo mi in methodinfos)  
  46.             {  
  47.                 if (mi.IsVirtual)  
  48.                 {  
  49.   
  50.                     string theRetType = mi.ReturnType.FullName;  
  51.                     if (mi.ReturnType == typeof(void))  
  52.                     {  
  53.                         theRetType = "void";  
  54.                     }  
  55.                     string theParams = "";  
  56.                     string theTypes = "";  
  57.                     string thePMInsts = "";  
  58.                     ParameterInfo[] thePs = mi.GetParameters();  
  59.                     for (int i = 0; i < thePs.Length; i++)  
  60.                     {  
  61.   
  62.                         if (i == 0)  
  63.                         {  
  64.                             theTypes = "typeof(" + thePs[i].ParameterType.FullName + ")";  
  65.                             if (thePs[i].IsOut)  
  66.                             {  
  67.                                 theParams = "out " + thePs[i].ParameterType.FullName + " " + thePs[i].Name;  
  68.                                 thePMInsts = "out " + thePs[i].Name;  
  69.                             }  
  70.                             else  
  71.                             {  
  72.                                 theParams = "" + thePs[i].ParameterType.FullName + " " + thePs[i].Name;  
  73.                                 thePMInsts = "" + thePs[i].Name;  
  74.                             }  
  75.                         }  
  76.                         else  
  77.                         {  
  78.                             theTypes = ",typeof(" + thePs[i].ParameterType.FullName + ")";  
  79.                             if (thePs[i].IsOut)  
  80.                             {  
  81.                                 thePMInsts = ",out " + thePs[i].Name;  
  82.                                 theParams = ",out " + thePs[i].ParameterType.FullName + " " + thePs[i].Name;  
  83.                             }  
  84.                             else  
  85.                             {  
  86.                                 thePMInsts = "," + thePs[i].Name;  
  87.                                 theParams = "," + thePs[i].ParameterType.FullName + " " + thePs[i].Name;  
  88.                             }  
  89.                         }  
  90.                     }  
  91.   
  92.                     theClassBuilder.AppendLine("   public override " + theRetType + " " + mi.Name + "(" + theParams + ")");  
  93.                     theClassBuilder.AppendLine("   {");  
  94.                     theClassBuilder.AppendLine("   if (_adviceList != null)");  
  95.                     theClassBuilder.AppendLine("   {");  
  96.                     theClassBuilder.AppendLine("       foreach (IMethodInterceptor item in _adviceList)");  
  97.                     theClassBuilder.AppendLine("       {");  
  98.                     theClassBuilder.AppendLine("           MethodInfo theMI = _target.GetType().GetMethod(\"" + mi.Name + "\", new Type[] { " + theTypes + "});");  
  99.                     theClassBuilder.AppendLine("           AdviseInvocation theInvocation = new AdviseInvocation(_target, theMI, new object[]{" + thePMInsts + "});");  
  100.                     if (mi.ReturnType == typeof(void))  
  101.                     {  
  102.                         theClassBuilder.AppendLine("           item.Invoke(theInvocation);");  
  103.                     }  
  104.                     else  
  105.                     {  
  106.                         theClassBuilder.AppendLine("           return (" + theRetType + ")(item.Invoke(theInvocation));");  
  107.                     }  
  108.                     theClassBuilder.AppendLine("      }");  
  109.   
  110.                     theClassBuilder.AppendLine("   }");  
  111.                     if (mi.ReturnType == typeof(void))  
  112.                     {  
  113.                         theClassBuilder.AppendLine("     _target." + mi.Name + "(" + thePMInsts + ");");  
  114.                     }  
  115.                     else  
  116.                     {  
  117.                         theClassBuilder.AppendLine("  return (" + theRetType + ")(_target." + mi.Name + "(" + thePMInsts + "));");  
  118.                     }  
  119.                     theClassBuilder.AppendLine("}");  
  120.                 }  
  121.             }  
  122.             theClassBuilder.AppendLine("}");  
  123.             theClassBuilder.AppendLine("}");  
  124.   
  125.            //测试观察用  
  126.             Console.WriteLine(theClassBuilder.ToString());  
  127.   
  128.             //===============================动态编译代理类代码====================================  
  129.             //创建编译器实例。     
  130.             CSharpCodeProvider provider = new CSharpCodeProvider();  
  131.             //设置编译参数。     
  132.             CompilerParameters paras = new CompilerParameters();  
  133.             paras.GenerateExecutable = false;  
  134.             paras.GenerateInMemory = true;  
  135.             //paras.ReferencedAssemblies.Add("System.dll");  
  136.             paras.ReferencedAssemblies.Add("SpringNetStudy.exe");  
  137.             //paras.ReferencedAssemblies.Add("mscorlib.dll");  
  138.             //paras.ReferencedAssemblies.Add("");  
  139.             //编译代码。     
  140.             CompilerResults result = provider.CompileAssemblyFromSource(paras, theClassBuilder.ToString());  
  141.   
  142.             //获取编译后的程序集。     
  143.             Assembly assembly = result.CompiledAssembly;  
  144.             Type theType = assembly.GetType(theTargetType.Namespace+"."+ theProxyClassName,false,true);  
  145.             var obj = Activator.CreateInstance(theType, new object[] {_target,_adviceList});  
  146.             return obj;  
  147.         }  
  148.     }  


后记:有些东西看起来很神秘,但实际上也不过如此。国内没法做出好的框架,其实一个主要的原因就是编译技术不过关,没有自己的语言。如果Emit和动态编译命名空间的方法不公开,就很难做了.

0 0