准备工作完成后,DynamicProxy类就可以开始了。
创建代理对象 Create
创建代理对象主要分为五步:
(1)、获取被代理类型构造函数参数列表
Type[] parameterTypes = parameters == null ? Type.EmptyTypes : parameters.Select(p => p.GetType()).ToArray();
(2)、根据构造函数参数列表创建代理类型
Type proxyType = CreateProxyType(srcType, parameterTypes);
(3)、使用动态方法生成创建代理类型实例的委托
CreateFunc<T>(proxyType, parameterTypes)
(4)、生成ProxyType对象,存入代理类型字典,以备二次调用
obj = new ProxyType<T>(srcType.FullName, signature, CreateFunc<T>(proxyType, parameterTypes)); func_Dictionary.Add(srcType.FullName + "(" + signature + ")", obj);
(5)、通过委托生成代理对象
Func<object[], T> func = (obj as ProxyType<T>).CreateFunc;
if (func == null)
throw new Exception("unknown exception");
return func(parameters);
1 /// <summary> 2 /// 创建代理类型 3 /// </summary> 4 /// <param name="srcType">类型</param> 5 /// <param name="parameterTypes">参数</param> 6 /// <returns></returns> 7 private static Type CreateProxyType(Type srcType, Type[] parameterTypes) 8 { 9 XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection 10 (srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); 11 12 13 foreach (var propertyInfo in srcType.GetProperties()) 14 OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); 15 16 //切入方法 17 MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); 18 19 for (int i = 0; i < methods.Length; i++) 20 { 21 var method = methods[i]; 22 23 if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; 24 25 object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); 26 27 OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes); 28 } 29 30 Type result = bc.DynamicTypeBuilder.CreateType(); 31 32 bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); 33 34 return result; 35 }
1.1、根据构造函数参数列表创建代理类型 CreateProxyType
(1)、通过Emit生成动态程序集、动态模块以及动态类型
XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
(srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes);
(2)、重写被切入的属性
OverrideProperty(bc.DynamicTypeBuilder, propertyInfo);
(3)、重写被切入的方法
OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);
(4)、生成代理类型
Type result = bc.DynamicTypeBuilder.CreateType();
1 /// <summary> 2 /// 创建代理类型 3 /// </summary> 4 /// <param name="srcType">类型</param> 5 /// <param name="parameterTypes">参数</param> 6 /// <returns></returns> 7 private static Type CreateProxyType(Type srcType, Type[] parameterTypes) 8 { 9 XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection 10 (srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); 11 12 13 foreach (var propertyInfo in srcType.GetProperties()) 14 OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); 15 16 //切入方法 17 MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); 18 19 for (int i = 0; i < methods.Length; i++) 20 { 21 var method = methods[i]; 22 23 if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; 24 25 object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); 26 27 OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes); 28 } 29 30 Type result = bc.DynamicTypeBuilder.CreateType(); 31 32 bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); 33 34 return result; 35 }
1.1.1 重写被切入的属性 OverrideProperty
1 /// <summary> 2 /// 重写被代理类的属性 3 /// </summary> 4 /// <param name="dynamicTypeBuilder"></param> 5 /// <param name="info">属性信息</param> 6 /// <param name="rangeType">切面范围</param> 7 /// <param name="onEntryExit">切面公共调用方法</param> 8 private static void OverrideProperty(TypeBuilder dynamicTypeBuilder, PropertyInfo info) 9 { 10 //不需要切入直接返回 11 object[] aspectAttributes = info.GetCustomAttributes(typeof(AspectAttribute), false); 12 13 if (aspectAttributes.Length == 0) return; 14 15 PropertyBuilder dynamicPropertyBuilder = dynamicTypeBuilder.DefineProperty(info.Name, PropertyAttributes.HasDefault, info.PropertyType, null); 16 17 //Getter Setter 方法标识 18 MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual; 19 20 MethodBuilder getter = dynamicTypeBuilder.DefineMethod("get_" + info.Name, getSetAttr, info.PropertyType, Type.EmptyTypes); 21 22 ILGenerator getIL = getter.GetILGenerator(); 23 24 ILGenerateProxyMethod(getIL, info.GetGetMethod(), Type.EmptyTypes, aspectAttributes); 25 26 27 //覆盖自动生成的Getter 28 MethodInfo getMethod = info.GetGetMethod(); 29 30 if (getMethod != null) dynamicTypeBuilder.DefineMethodOverride(getter, getMethod); 31 32 //给属性设置Get、Set方法 33 dynamicPropertyBuilder.SetGetMethod(getter); 34 35 36 //重写Set 方法 37 MethodBuilder setter = dynamicTypeBuilder.DefineMethod("set_" + info.Name, getSetAttr, typeof(void), new Type[] { info.PropertyType }); 38 39 ILGenerator setIL = setter.GetILGenerator(); 40 41 ILGenerateProxyMethod(setIL, info.GetSetMethod(), new Type[] { info.PropertyType }, aspectAttributes); 42 43 44 //覆盖自动生成的Setter 45 MethodInfo setMethod = info.GetSetMethod(); 46 47 if (setMethod != null) dynamicTypeBuilder.DefineMethodOverride(setter, setMethod); 48 49 dynamicPropertyBuilder.SetSetMethod(setter); 50 }
1.1.2 重写被切入的方法 OverrideMethod
1 /// <summary> 2 /// 重写被代理类的指定方法 3 /// </summary> 4 /// <param name="typeBuilder">类型</param> 5 /// <param name="src_Method">被代理方法</param> 6 /// <param name="aspectAttributes">代理特性集合</param> 7 private static void OverrideMethod(TypeBuilder typeBuilder, MethodInfo src_Method, object[] aspectAttributes) 8 { 9 if (aspectAttributes == null || aspectAttributes.Length == 0) return; 10 11 MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual; 12 13 //获取当前方法参数列表 14 Type[] paramTypes = XDynamic.GetMethodParameterTypes(src_Method); 15 16 ILGenerator il = typeBuilder.DefineMethod(src_Method.Name, attr, src_Method.ReturnType, paramTypes).GetILGenerator(); 17 18 ILGenerateProxyMethod(il, src_Method, paramTypes, aspectAttributes); 19 }
1.1.3 生成代理方法 ILGenerateProxyMethod
1 /// <summary> 2 /// 3 /// </summary> 4 /// <param name="il_ProxyMethod"></param> 5 /// <param name="src_Method"></param> 6 /// <param name="paramTypes"></param> 7 /// <param name="aspectAttributes"></param> 8 private static void ILGenerateProxyMethod(ILGenerator il_ProxyMethod, MethodInfo src_Method, Type[] paramTypes, object[] aspectAttributes) 9 { 10 int aspectCount = aspectAttributes.Length; 11 12 //生成切面上下文 13 LocalBuilder aspectContext = CreateAspectContext(il_ProxyMethod, src_Method.Name, paramTypes); 14 15 //申明临时存放切面对象和OnExit方法的变量 16 var aspectLocalBuilders = new LocalBuilder[aspectCount]; 17 var onExit_Methods = new MethodInfo[aspectCount]; 18 19 20 //初始化标记的切面对象,并调用切面对象的OnEntry方法 21 for (int i = 0; i < aspectCount; i++) 22 { 23 //创建一个切面对象 24 var aspectType = aspectAttributes[i].GetType(); 25 var aspect = il_ProxyMethod.DeclareLocal(aspectType); 26 ConstructorInfo constructor = aspectType.GetConstructor(Type.EmptyTypes); 27 28 il_ProxyMethod.Emit(OpCodes.Newobj, constructor); 29 il_ProxyMethod.Emit(OpCodes.Stloc, aspect); 30 31 var onEntry_method = aspectType.GetMethod("OnEntry"); 32 onExit_Methods[i] = aspectType.GetMethod("OnExit"); 33 34 //调用BeforeInvoke 35 il_ProxyMethod.Emit(OpCodes.Ldloc, aspect); 36 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); 37 il_ProxyMethod.Emit(OpCodes.Callvirt, onEntry_method); 38 il_ProxyMethod.Emit(OpCodes.Nop); 39 40 aspectLocalBuilders[i] = aspect; 41 } 42 43 //类对象,参数值依次入栈 44 for (int i = 0; i <= paramTypes.Length; i++) 45 il_ProxyMethod.Emit(OpCodes.Ldarg, i); 46 47 //调用基类的方法 48 il_ProxyMethod.Emit(OpCodes.Call, src_Method); 49 50 51 //定义返回值 52 LocalBuilder result = null; 53 54 //如果有返回值,保存返回值到局部变量 55 if (src_Method.ReturnType != typeof(void)) 56 { 57 result = il_ProxyMethod.DeclareLocal(src_Method.ReturnType); 58 il_ProxyMethod.Emit(OpCodes.Stloc, result); 59 60 //给AspectContext的属性Result赋值 61 var resultSetMethod = typeof(AspectContext).GetMethod("set_Result"); 62 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量 63 il_ProxyMethod.Emit(OpCodes.Ldloc, result);//加载返回值 64 il_ProxyMethod.Emit(OpCodes.Box, src_Method.ReturnType); 65 il_ProxyMethod.Emit(OpCodes.Call, resultSetMethod);//赋值 66 } 67 68 //调用横切对象的OnExit方法 69 for (int i = 0; i < aspectCount; i++) 70 { 71 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectLocalBuilders[i]); 72 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); 73 il_ProxyMethod.Emit(OpCodes.Callvirt, onExit_Methods[i]); 74 il_ProxyMethod.Emit(OpCodes.Nop); 75 } 76 77 //如果有返回值,则把返回值压栈 78 if (result != null) 79 il_ProxyMethod.Emit(OpCodes.Ldloc, result); 80 81 il_ProxyMethod.Emit(OpCodes.Ret);//返回 82 }
1.1.4 生成切面上下文对象 CreateAspectContext
1 /// <summary> 2 /// 生成切面上下文对象 3 /// </summary> 4 /// <param name="il"></param> 5 /// <param name="methodName">方法名称</param> 6 /// <param name="paramTypes">参数类型</param> 7 /// <returns></returns> 8 private static LocalBuilder CreateAspectContext(ILGenerator il, string methodName, Type[] paramTypes) 9 { 10 //AspectContext.ParameterArgs 类型为 object[] 11 12 //声明一个类型为object的局部数组 13 il.DeclareLocal(typeof(object[])); 14 //数组长度入栈 15 il.Emit(OpCodes.Ldc_I4, paramTypes.Length); 16 //生成新数组 17 il.Emit(OpCodes.Newarr, typeof(object)); 18 //赋值给局部数组变量 19 il.Emit(OpCodes.Stloc_0); 20 21 //遍历参数,并存入数组 22 for (int i = 0; i < paramTypes.Length; i++) 23 { 24 il.Emit(OpCodes.Ldloc_0);//数组入栈 25 il.Emit(OpCodes.Ldc_I4, i);//数组下标入栈 26 il.Emit(OpCodes.Ldarg, i + 1);//按下标加载对应的参数 27 if (paramTypes[i].IsValueType)//参数为值类型,装箱 28 il.Emit(OpCodes.Box, paramTypes[i]); 29 il.Emit(OpCodes.Stelem_Ref);//将参数存入数组 30 } 31 32 //获取AspectContext构造函数 33 Type aspectContextType = typeof(AspectContext); 34 ConstructorInfo info = aspectContextType.GetConstructor(new Type[] { typeof(object), typeof(string), typeof(object[]) }); 35 36 //生成一个AspectContext 对象 37 il.Emit(OpCodes.Ldarg_0);//加载调用对象 38 il.Emit(OpCodes.Ldstr, methodName);//加载方法名称 39 il.Emit(OpCodes.Ldloc_0);//加载由参数生成的局部数组变量 40 il.Emit(OpCodes.Newobj, info); 41 42 //声明一个AspectContext局部变量 43 LocalBuilder aspectContext = il.DeclareLocal(aspectContextType); 44 il.Emit(OpCodes.Stloc, aspectContext); 45 46 return aspectContext; 47 }
1.2 使用动态方法生成创建代理类型实例的委托
1 /// <summary> 2 /// 生成创建代理类型实例的委托 3 /// </summary> 4 /// <typeparam name="T">被代理类型</typeparam> 5 /// <param name="proxyType">代理类型</param> 6 /// <param name="parameterTypes">代理类型构造函数参数类型</param> 7 /// <returns></returns> 8 private static Func<object[], T> CreateFunc<T>(Type proxyType, Type[] parameterTypes) 9 { 10 DynamicMethod method = new DynamicMethod(proxyType.Name + "_CF", typeof(T), new Type[] { typeof(object[]) }, true); 11 12 var il = method.GetILGenerator(); 13 14 //根据T类型的构造函数参数列表,依次将 object[] parameters 中对应的值加载到堆栈(并做相应类型转换),以被T类型的构造函数使用 15 for (int i = 0; i < parameterTypes.Length; i++) 16 { 17 18 il.Emit(OpCodes.Ldarg_0); 19 il.Emit(OpCodes.Ldc_I4, i); 20 il.Emit(OpCodes.Ldelem_Ref); 21 22 if (parameterTypes[i].IsValueType) 23 // 如果是值类型,拆箱 24 il.Emit(OpCodes.Unbox_Any, parameterTypes[i]); 25 else 26 // 如果是引用类型,转换 27 il.Emit(OpCodes.Castclass, parameterTypes[i]); 28 } 29 30 ConstructorInfo info = proxyType.GetConstructor(parameterTypes); 31 32 if (info == null) throw new Exception("代理类不存在,与指定参数列表相对应的构造函数。"); 33 34 il.Emit(OpCodes.Newobj, info); 35 il.Emit(OpCodes.Ret); 36 37 //建立《生成指定类型T的实例》的委托 38 return method.CreateDelegate(typeof(Func<object[], T>)) as Func<object[], T>; 39 }
1.3 ProxyType类
1 public class ProxyType<T> 2 { 3 #region 构造函数 4 /// <summary> 5 /// 构造函数 6 /// </summary> 7 /// <param name="name">类型名称</param> 8 /// <param name="parameterSignature">构造函数参数签名</param> 9 /// <param name="createFunc">创建被代理类型实例的委托</param> 10 public ProxyType(string name, string parameterSignature, Func<object[], T> createFunc) 11 { 12 Name = name; ParameterSignature = parameterSignature; CreateFunc = createFunc; 13 } 14 #endregion 15 16 #region 属性 17 18 /// <summary> 19 /// 名称 20 /// </summary> 21 public string Name { get; set; } 22 23 /// <summary> 24 /// 参数类型签名 25 /// </summary> 26 public string ParameterSignature { get; set; } 27 28 /// <summary> 29 /// 创建被代理类型实例的委托 30 /// </summary> 31 public Func<object[], T> CreateFunc { get; set; } 32 33 #endregion 34 }
到此为止一个简单的Aop框架就完成了。下一篇会介绍一个下BuilderCollection类