目 录
准备工作完成后,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);
/// <summary>
/// 创建代理类型
/// </summary>
/// <param name="srcType">类型</param>
/// <param name="parameterTypes">参数</param>
/// <returns></returns>
private static Type CreateProxyType(Type srcType, Type[] parameterTypes)
{
XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
(srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); foreach (var propertyInfo in srcType.GetProperties())
OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); //切入方法
MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); for (int i = ; i < methods.Length; i++)
{
var method = methods[i]; if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);
} Type result = bc.DynamicTypeBuilder.CreateType(); bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); return result;
}
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();
/// <summary>
/// 创建代理类型
/// </summary>
/// <param name="srcType">类型</param>
/// <param name="parameterTypes">参数</param>
/// <returns></returns>
private static Type CreateProxyType(Type srcType, Type[] parameterTypes)
{
XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
(srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); foreach (var propertyInfo in srcType.GetProperties())
OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); //切入方法
MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); for (int i = ; i < methods.Length; i++)
{
var method = methods[i]; if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);
} Type result = bc.DynamicTypeBuilder.CreateType(); bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); return result;
}
1.1.1 重写被切入的属性 OverrideProperty
/// <summary>
/// 重写被代理类的属性
/// </summary>
/// <param name="dynamicTypeBuilder"></param>
/// <param name="info">属性信息</param>
/// <param name="rangeType">切面范围</param>
/// <param name="onEntryExit">切面公共调用方法</param>
private static void OverrideProperty(TypeBuilder dynamicTypeBuilder, PropertyInfo info)
{
//不需要切入直接返回
object[] aspectAttributes = info.GetCustomAttributes(typeof(AspectAttribute), false); if (aspectAttributes.Length == ) return; PropertyBuilder dynamicPropertyBuilder = dynamicTypeBuilder.DefineProperty(info.Name, PropertyAttributes.HasDefault, info.PropertyType, null); //Getter Setter 方法标识
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual; MethodBuilder getter = dynamicTypeBuilder.DefineMethod("get_" + info.Name, getSetAttr, info.PropertyType, Type.EmptyTypes); ILGenerator getIL = getter.GetILGenerator(); ILGenerateProxyMethod(getIL, info.GetGetMethod(), Type.EmptyTypes, aspectAttributes); //覆盖自动生成的Getter
MethodInfo getMethod = info.GetGetMethod(); if (getMethod != null) dynamicTypeBuilder.DefineMethodOverride(getter, getMethod); //给属性设置Get、Set方法
dynamicPropertyBuilder.SetGetMethod(getter); //重写Set 方法
MethodBuilder setter = dynamicTypeBuilder.DefineMethod("set_" + info.Name, getSetAttr, typeof(void), new Type[] { info.PropertyType }); ILGenerator setIL = setter.GetILGenerator(); ILGenerateProxyMethod(setIL, info.GetSetMethod(), new Type[] { info.PropertyType }, aspectAttributes); //覆盖自动生成的Setter
MethodInfo setMethod = info.GetSetMethod(); if (setMethod != null) dynamicTypeBuilder.DefineMethodOverride(setter, setMethod); dynamicPropertyBuilder.SetSetMethod(setter);
}
1.1.2 重写被切入的方法 OverrideMethod
/// <summary>
/// 重写被代理类的指定方法
/// </summary>
/// <param name="typeBuilder">类型</param>
/// <param name="src_Method">被代理方法</param>
/// <param name="aspectAttributes">代理特性集合</param>
private static void OverrideMethod(TypeBuilder typeBuilder, MethodInfo src_Method, object[] aspectAttributes)
{
if (aspectAttributes == null || aspectAttributes.Length == ) return; MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual; //获取当前方法参数列表
Type[] paramTypes = XDynamic.GetMethodParameterTypes(src_Method); ILGenerator il = typeBuilder.DefineMethod(src_Method.Name, attr, src_Method.ReturnType, paramTypes).GetILGenerator(); ILGenerateProxyMethod(il, src_Method, paramTypes, aspectAttributes);
}
1.1.3 生成代理方法 ILGenerateProxyMethod
/// <summary>
///
/// </summary>
/// <param name="il_ProxyMethod"></param>
/// <param name="src_Method"></param>
/// <param name="paramTypes"></param>
/// <param name="aspectAttributes"></param>
private static void ILGenerateProxyMethod(ILGenerator il_ProxyMethod, MethodInfo src_Method, Type[] paramTypes, object[] aspectAttributes)
{
int aspectCount = aspectAttributes.Length; //生成切面上下文
LocalBuilder aspectContext = CreateAspectContext(il_ProxyMethod, src_Method.Name, paramTypes); //申明临时存放切面对象和OnExit方法的变量
var aspectLocalBuilders = new LocalBuilder[aspectCount];
var onExit_Methods = new MethodInfo[aspectCount]; //初始化标记的切面对象,并调用切面对象的OnEntry方法
for (int i = ; i < aspectCount; i++)
{
//创建一个切面对象
var aspectType = aspectAttributes[i].GetType();
var aspect = il_ProxyMethod.DeclareLocal(aspectType);
ConstructorInfo constructor = aspectType.GetConstructor(Type.EmptyTypes); il_ProxyMethod.Emit(OpCodes.Newobj, constructor);
il_ProxyMethod.Emit(OpCodes.Stloc, aspect); var onEntry_method = aspectType.GetMethod("OnEntry");
onExit_Methods[i] = aspectType.GetMethod("OnExit"); //调用BeforeInvoke
il_ProxyMethod.Emit(OpCodes.Ldloc, aspect);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, onEntry_method);
il_ProxyMethod.Emit(OpCodes.Nop); aspectLocalBuilders[i] = aspect;
} //类对象,参数值依次入栈
for (int i = ; i <= paramTypes.Length; i++)
il_ProxyMethod.Emit(OpCodes.Ldarg, i); //调用基类的方法
il_ProxyMethod.Emit(OpCodes.Call, src_Method); //定义返回值
LocalBuilder result = null; //如果有返回值,保存返回值到局部变量
if (src_Method.ReturnType != typeof(void))
{
result = il_ProxyMethod.DeclareLocal(src_Method.ReturnType);
il_ProxyMethod.Emit(OpCodes.Stloc, result); //给AspectContext的属性Result赋值
var resultSetMethod = typeof(AspectContext).GetMethod("set_Result");
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量
il_ProxyMethod.Emit(OpCodes.Ldloc, result);//加载返回值
il_ProxyMethod.Emit(OpCodes.Box, src_Method.ReturnType);
il_ProxyMethod.Emit(OpCodes.Call, resultSetMethod);//赋值
} //调用横切对象的OnExit方法
for (int i = ; i < aspectCount; i++)
{
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectLocalBuilders[i]);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, onExit_Methods[i]);
il_ProxyMethod.Emit(OpCodes.Nop);
} //如果有返回值,则把返回值压栈
if (result != null)
il_ProxyMethod.Emit(OpCodes.Ldloc, result); il_ProxyMethod.Emit(OpCodes.Ret);//返回
}
1.1.4 生成切面上下文对象 CreateAspectContext
/// <summary>
/// 生成切面上下文对象
/// </summary>
/// <param name="il"></param>
/// <param name="methodName">方法名称</param>
/// <param name="paramTypes">参数类型</param>
/// <returns></returns>
private static LocalBuilder CreateAspectContext(ILGenerator il, string methodName, Type[] paramTypes)
{
//AspectContext.ParameterArgs 类型为 object[] //声明一个类型为object的局部数组
il.DeclareLocal(typeof(object[]));
//数组长度入栈
il.Emit(OpCodes.Ldc_I4, paramTypes.Length);
//生成新数组
il.Emit(OpCodes.Newarr, typeof(object));
//赋值给局部数组变量
il.Emit(OpCodes.Stloc_0); //遍历参数,并存入数组
for (int i = ; i < paramTypes.Length; i++)
{
il.Emit(OpCodes.Ldloc_0);//数组入栈
il.Emit(OpCodes.Ldc_I4, i);//数组下标入栈
il.Emit(OpCodes.Ldarg, i + );//按下标加载对应的参数
if (paramTypes[i].IsValueType)//参数为值类型,装箱
il.Emit(OpCodes.Box, paramTypes[i]);
il.Emit(OpCodes.Stelem_Ref);//将参数存入数组
} //获取AspectContext构造函数
Type aspectContextType = typeof(AspectContext);
ConstructorInfo info = aspectContextType.GetConstructor(new Type[] { typeof(object), typeof(string), typeof(object[]) }); //生成一个AspectContext 对象
il.Emit(OpCodes.Ldarg_0);//加载调用对象
il.Emit(OpCodes.Ldstr, methodName);//加载方法名称
il.Emit(OpCodes.Ldloc_0);//加载由参数生成的局部数组变量
il.Emit(OpCodes.Newobj, info); //声明一个AspectContext局部变量
LocalBuilder aspectContext = il.DeclareLocal(aspectContextType);
il.Emit(OpCodes.Stloc, aspectContext); return aspectContext;
}
1.2 使用动态方法生成创建代理类型实例的委托
/// <summary>
/// 生成创建代理类型实例的委托
/// </summary>
/// <typeparam name="T">被代理类型</typeparam>
/// <param name="proxyType">代理类型</param>
/// <param name="parameterTypes">代理类型构造函数参数类型</param>
/// <returns></returns>
private static Func<object[], T> CreateFunc<T>(Type proxyType, Type[] parameterTypes)
{
DynamicMethod method = new DynamicMethod(proxyType.Name + "_CF", typeof(T), new Type[] { typeof(object[]) }, true); var il = method.GetILGenerator(); //根据T类型的构造函数参数列表,依次将 object[] parameters 中对应的值加载到堆栈(并做相应类型转换),以被T类型的构造函数使用
for (int i = ; i < parameterTypes.Length; i++)
{ il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref); if (parameterTypes[i].IsValueType)
// 如果是值类型,拆箱
il.Emit(OpCodes.Unbox_Any, parameterTypes[i]);
else
// 如果是引用类型,转换
il.Emit(OpCodes.Castclass, parameterTypes[i]);
} ConstructorInfo info = proxyType.GetConstructor(parameterTypes); if (info == null) throw new Exception("代理类不存在,与指定参数列表相对应的构造函数。"); il.Emit(OpCodes.Newobj, info);
il.Emit(OpCodes.Ret); //建立《生成指定类型T的实例》的委托
return method.CreateDelegate(typeof(Func<object[], T>)) as Func<object[], T>;
}
1.3 ProxyType类
public class ProxyType<T>
{
#region 构造函数
/// <summary>
/// 构造函数
/// </summary>
/// <param name="name">类型名称</param>
/// <param name="parameterSignature">构造函数参数签名</param>
/// <param name="createFunc">创建被代理类型实例的委托</param>
public ProxyType(string name, string parameterSignature, Func<object[], T> createFunc)
{
Name = name; ParameterSignature = parameterSignature; CreateFunc = createFunc;
}
#endregion #region 属性 /// <summary>
/// 名称
/// </summary>
public string Name { get; set; } /// <summary>
/// 参数类型签名
/// </summary>
public string ParameterSignature { get; set; } /// <summary>
/// 创建被代理类型实例的委托
/// </summary>
public Func<object[], T> CreateFunc { get; set; } #endregion
}
到此为止一个简单的Aop框架就完成了。下一篇会介绍一个下BuilderCollection类