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

来源:互联网 发布:php点击按钮运算 编辑:程序博客网 时间:2024/05/21 08:48

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

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

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

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


护的虚方法.

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

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

 

 

public class MyProxyFactory    {        object _target;        private List<IMethodInterceptor> _adviceList = new List<IMethodInterceptor>();       //所谓的前置,后置等通知性类,其实就是要注入的间谍。        public void Add(IMethodInterceptor advice)        {            _adviceList.Add(advice);        }       //构造函数,传入目标对象.        public MyProxyFactory(object target)        {            _target = target;        }       // 创建并放回代理类。注意,这里是每次都创建,实际上是可以缓存的.        public object GetProxyClass()        {            StringBuilder theClassBuilder = new StringBuilder();            Type theTargetType = _target.GetType();            string theProxyClassName = "__" + theTargetType.Name + "_Proxy";                        theClassBuilder.AppendLine("using System;");            theClassBuilder.AppendLine("using System.Collections.Generic;");            theClassBuilder.AppendLine("using System.Text;");            theClassBuilder.AppendLine("using System.Reflection;");            theClassBuilder.AppendLine("using System.Reflection.Emit;");            theClassBuilder.AppendLine("namespace " + theTargetType.Namespace);            theClassBuilder.AppendLine("{");            theClassBuilder.AppendLine("public class "+theProxyClassName+" : " + theTargetType.FullName + "{");            theClassBuilder.AppendLine("   private " + theTargetType.FullName + " _target;");            theClassBuilder.AppendLine("   private List<IMethodInterceptor> _adviceList = null;");            theClassBuilder.AppendLine("   public __" + theTargetType.Name + "_Proxy(" + theTargetType.FullName + " target, List<IMethodInterceptor> AdviceList)");            theClassBuilder.AppendLine("   {");            theClassBuilder.AppendLine("   _target = target;");            theClassBuilder.AppendLine("   this._adviceList = AdviceList;");            theClassBuilder.AppendLine("   }");            //获取目标类的方法,准备给代理类继承            MethodInfo[] methodinfos = theTargetType.GetMethods(BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance);            foreach (MethodInfo mi in methodinfos)            {                if (mi.IsVirtual)                {                    string theRetType = mi.ReturnType.FullName;                    if (mi.ReturnType == typeof(void))                    {                        theRetType = "void";                    }                    string theParams = "";                    string theTypes = "";                    string thePMInsts = "";                    ParameterInfo[] thePs = mi.GetParameters();                    for (int i = 0; i < thePs.Length; i++)                    {                        if (i == 0)                        {                            theTypes = "typeof(" + thePs[i].ParameterType.FullName + ")";                            if (thePs[i].IsOut)                            {                                theParams = "out " + thePs[i].ParameterType.FullName + " " + thePs[i].Name;                                thePMInsts = "out " + thePs[i].Name;                            }                            else                            {                                theParams = "" + thePs[i].ParameterType.FullName + " " + thePs[i].Name;                                thePMInsts = "" + thePs[i].Name;                            }                        }                        else                        {                            theTypes = ",typeof(" + thePs[i].ParameterType.FullName + ")";                            if (thePs[i].IsOut)                            {                                thePMInsts = ",out " + thePs[i].Name;                                theParams = ",out " + thePs[i].ParameterType.FullName + " " + thePs[i].Name;                            }                            else                            {                                thePMInsts = "," + thePs[i].Name;                                theParams = "," + thePs[i].ParameterType.FullName + " " + thePs[i].Name;                            }                        }                    }                    theClassBuilder.AppendLine("   public override " + theRetType + " " + mi.Name + "(" + theParams + ")");                    theClassBuilder.AppendLine("   {");                    theClassBuilder.AppendLine("   if (_adviceList != null)");                    theClassBuilder.AppendLine("   {");                    theClassBuilder.AppendLine("       foreach (IMethodInterceptor item in _adviceList)");                    theClassBuilder.AppendLine("       {");                    theClassBuilder.AppendLine("           MethodInfo theMI = _target.GetType().GetMethod(\"" + mi.Name + "\", new Type[] { " + theTypes + "});");                    theClassBuilder.AppendLine("           AdviseInvocation theInvocation = new AdviseInvocation(_target, theMI, new object[]{" + thePMInsts + "});");                    if (mi.ReturnType == typeof(void))                    {                        theClassBuilder.AppendLine("           item.Invoke(theInvocation);");                    }                    else                    {                        theClassBuilder.AppendLine("           return (" + theRetType + ")(item.Invoke(theInvocation));");                    }                    theClassBuilder.AppendLine("      }");                    theClassBuilder.AppendLine("   }");                    if (mi.ReturnType == typeof(void))                    {                        theClassBuilder.AppendLine("     _target." + mi.Name + "(" + thePMInsts + ");");                    }                    else                    {                        theClassBuilder.AppendLine("  return (" + theRetType + ")(_target." + mi.Name + "(" + thePMInsts + "));");                    }                    theClassBuilder.AppendLine("}");                }            }            theClassBuilder.AppendLine("}");            theClassBuilder.AppendLine("}");           //测试观察用            Console.WriteLine(theClassBuilder.ToString());            //===============================动态编译代理类代码====================================            //创建编译器实例。               CSharpCodeProvider provider = new CSharpCodeProvider();            //设置编译参数。               CompilerParameters paras = new CompilerParameters();            paras.GenerateExecutable = false;            paras.GenerateInMemory = true;            //paras.ReferencedAssemblies.Add("System.dll");            paras.ReferencedAssemblies.Add("SpringNetStudy.exe");            //paras.ReferencedAssemblies.Add("mscorlib.dll");            //paras.ReferencedAssemblies.Add("");            //编译代码。               CompilerResults result = provider.CompileAssemblyFromSource(paras, theClassBuilder.ToString());            //获取编译后的程序集。               Assembly assembly = result.CompiledAssembly;            Type theType = assembly.GetType(theTargetType.Namespace+"."+ theProxyClassName,false,true);            var obj = Activator.CreateInstance(theType, new object[] {_target,_adviceList});            return obj;        }    }


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