使用Emit实现代理方式AOP框架
前几天开发项目中需要用到AOP,于是翻看了一些开源的AOP框架资料,发现对于我的需求都过于复杂,要求的配置很多,最后决定自己动手开发一个MINI的AOP框架。说干就干,查了一些资料决定采用Emit注入生成代理类的方式实现。
前几天开发项目中需要用到AOP,于是翻看了一些开源的AOP框架资料,这些框架功能都很强大,不过对于我来说这些强大的功能确显得有些繁琐,于是就想自己动手开发一个简单实用AOP框架。说干就干,查了一些资料决定采用Emit注入生成代理类的方式实现。
思路:分为两种情况,第一种是原始类从接口或抽象类继承而来,第二种就是没有继承接口或者抽象类。对以第一种情况我们生成的代理类只要同样继承接口或者抽象类然后引用原始类实例就可以,在方法中直接调用原始类中相应的方法,第二种情况继承原始类然后重写要注入的方法,这就要求原始类要实现切面的方法必须是虚方法。
假设我们有一个类Info.cs这个类继承自IInfo.cs接口,我们的目的是为Info实现一个代理类在这个代理类中能过后做两件事:1.调用切面方法 2.调用原始类中的方法。下面两个图说明实现代理类的两种情况:
图1
图2
当然我们不可能手动的去写一个这样的代理类,我们应该动态产生一个代理类,这让我们想到了Emit,使用过Emit的人都知道它功能非常强大,有人说他是MS提供的万能中间语言介入机制。OK 我们现在要做的就是通过Emit发射中间语言动态生成一个代理类。
思路清晰了,就让我们开始具体行动吧。创建一个项目SimpleAOP,如下图:
图3
图4
BaseAttribute:在AOP方法上标注属性的基类,只有一个属性CallHandlerType,它记录表示了该属性的方法使用哪个Handler来拦截方法。
ICallHandler:向拦截方法中注入代码类的接口
Wraper:包装类,该类对原始类进行包装产生代理类。
MethodContext:被拦截方法的上下文,包括Executor:原始类的实力,MethodInfo:被拦截方法信息,ParametersValue:参数信息
代码如下:
BaseAttribute
using System;
namespace SimpleAOP.Attributes
{
[AttributeUsage(AttributeTargets.Method)]
public abstract class BaseAttribute : Attribute
{
public abstract Type CallHandlerType
{
get;
protected set;
}
}
}
using System;
namespace SimpleAOP.Attributes
{
[AttributeUsage(AttributeTargets.Method)]
public abstract class BaseAttribute : Attribute
{
public abstract Type CallHandlerType
{
get;
protected set;
}
}
}
ICallHandler.cs
namespace SimpleAOP
{
public interface ICallHandler
{
object Invoke(MethodContext method);
}
}
namespace SimpleAOP
{
public interface ICallHandler
{
object Invoke(MethodContext method);
}
}
MethodContext
using System.Reflection;
namespace SimpleAOP
{
/// <summary>
/// 原方法的上下文
/// </summary>
public class MethodContext
{
/// <summary>
/// 原方法的MethodInfo
/// </summary>
public MethodInfo MethodInfo
{
get;
set;
}
/// <summary>
/// 执行对象
/// </summary>
public object Executor
{
get;
set;
}
/// <summary>
/// 调用方法中的参数值
/// </summary>
public object[] ParametersValue
{
get;
set;
}
/// <summary>
/// 调用原方法
/// </summary>
/// <returns>返回原方法返回值</returns>
public object Invoke()
{
return MethodInfo.Invoke(Executor, ParametersValue);
}
}
}
using System.Reflection;
namespace SimpleAOP
{
/// <summary>
/// 原方法的上下文
/// </summary>
public class MethodContext
{
/// <summary>
/// 原方法的MethodInfo
/// </summary>
public MethodInfo MethodInfo
{
get;
set;
}
/// <summary>
/// 执行对象
/// </summary>
public object Executor
{
get;
set;
}
/// <summary>
/// 调用方法中的参数值
/// </summary>
public object[] ParametersValue
{
get;
set;
}
/// <summary>
/// 调用原方法
/// </summary>
/// <returns>返回原方法返回值</returns>
public object Invoke()
{
return MethodInfo.Invoke(Executor, ParametersValue);
}
}
}
Wraper
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace SimpleAOP
{
public class Wraper
{
private static IDictionary<string, object> _Cache = new Dictionary<string, object>();
public static T Wrap<T>(T sourceObj)
{
T returnObj;
string key = sourceObj.GetType().ToString() + "_" + typeof(T).ToString();
object aopObject;
if (!_Cache.TryGetValue(key, out aopObject))
{
Type returnType = typeof(T);
Type sourceType = sourceObj.GetType();
AppDomain currentAppDomain = AppDomain.CurrentDomain;
AssemblyName assyName = new AssemblyName(sourceType.Name + "_Aop_Assmely");
AssemblyBuilder assyBuilder = currentAppDomain.DefineDynamicAssembly(assyName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder modBuilder = assyBuilder.DefineDynamicModule(sourceType.Name + "_Aop_Module");
String newTypeName = sourceType.Name + "_Aop";
TypeAttributes newTypeAttribute = TypeAttributes.Class | TypeAttributes.Public;
Type newTypeParent;
Type[] newTypeInterfaces;
MethodAttributes methodAttributes = MethodAttributes.Public | MethodAttributes.Virtual;
if (returnType.IsInterface)
{
newTypeParent = null;
newTypeInterfaces = new Type[] { returnType };
}
else
{
newTypeParent = returnType;
newTypeInterfaces = new Type[0];
}
TypeBuilder typeBuilder = modBuilder.DefineType(newTypeName, newTypeAttribute, newTypeParent, newTypeInterfaces);
//创建字段
FieldBuilder fbuilder = typeBuilder.DefineField("_SourceObj", typeof(T), FieldAttributes.Public);
#region 创建构造函数
//ConstructorBuilder conBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(T) });
//ILGenerator conIlGen = conBuilder.GetILGenerator();
//conIlGen.Emit(OpCodes.Ldarg_0);
//conIlGen.Emit(OpCodes.Ldarg_1);
//conIlGen.Emit(OpCodes.Stfld, fbuilder);
//conIlGen.Emit(OpCodes.Ret);
#endregion
MethodInfo[] targetMethods = returnType.GetMethods();
foreach (MethodInfo targetMethod in targetMethods)
{
if ((!targetMethod.IsAbstract) &&(!targetMethod.IsVirtual))
{
continue;
}
#region 得到方法的各个参数的类型
ParameterInfo[] arrParamInfo = targetMethod.GetParameters();
int paramCount = arrParamInfo.Length;
Type[] paramType = new Type[paramCount];
for (int i = 0; i < paramCount; i++)
paramType[i] = arrParamInfo[i].ParameterType;
#endregion
#region 传入方法签名,得到方法生成器
MethodBuilder methodBuilder = typeBuilder.DefineMethod(targetMethod.Name, methodAttributes, targetMethod.ReturnType, paramType);
MethodInfo getTypeMI = typeof(object).GetMethod("GetType", new Type[] { });
MethodInfo getMethodMI = typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string), typeof(Type[]) });
#endregion
#region 定义局部变量
//得到IL生成器
ILGenerator ilGen = methodBuilder.GetILGenerator();
ilGen.DeclareLocal(typeof(MethodInfo), true); //loc0
ilGen.DeclareLocal(typeof(object[]), true);//loc1
ilGen.DeclareLocal(typeof(MethodContext), true);//loc2
ilGen.DeclareLocal(typeof(Type[]), true);//loc3
ilGen.DeclareLocal(typeof(Type), true);//loc4
#endregion
object[] aopAtts = sourceType.GetMethod(targetMethod.Name, paramType).GetCustomAttributes(typeof(SimpleAOP.Attributes.BaseAttribute), true);
if (aopAtts != null && aopAtts.Length > 0)//检测是否标注了AOP属性
{
Attributes.BaseAttribute apoAtt = (Attributes.BaseAttribute)aopAtts[0];
#region 获取sourceObj中的当前MethodInfo并存入loc0中
ilGen.Emit(OpCodes.Nop);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder);
ilGen.EmitCall(OpCodes.Call, getTypeMI, null);
ilGen.Emit(OpCodes.Stloc, 4);
#region 获取参数类型数组
ilGen.Emit(OpCodes.Ldc_I4, paramCount);
ilGen.Emit(OpCodes.Newarr, typeof(Type));
ilGen.Emit(OpCodes.Stloc_3);
ilGen.Emit(OpCodes.Ldloc_3);
for (int i = 0; i < paramCount; i++)
{
ilGen.Emit(OpCodes.Ldc_I4, i);
ilGen.Emit(OpCodes.Ldarg, (short)(i + 1));//arg0表示this,真正的方法参数从索引1开始
ilGen.Emit(OpCodes.Box, paramType[i]);//不装箱对一些类型的参数会出错
ilGen.EmitCall(OpCodes.Call, getTypeMI, null);
ilGen.Emit(OpCodes.Stelem_Ref);
}
#endregion
ilGen.Emit(OpCodes.Ldloc, 4);
ilGen.Emit(OpCodes.Ldstr, targetMethod.Name);
ilGen.Emit(OpCodes.Ldloc_3);
ilGen.EmitCall(OpCodes.Call, getMethodMI, null);
ilGen.Emit(OpCodes.Stloc_0);
#endregion
#region 获取参数并将其存入object[]类型变量loc1中
ilGen.Emit(OpCodes.Ldc_I4, paramCount);
ilGen.Emit(OpCodes.Newarr, typeof(object));
ilGen.Emit(OpCodes.Stloc_1);
ilGen.Emit(OpCodes.Ldloc_1);
for (int i = 0; i < paramCount; i++)
{
ilGen.Emit(OpCodes.Ldc_I4, i);
ilGen.Emit(OpCodes.Ldarg, (short)(i + 1));//arg0表示this,真正的方法参数从索引1开始
ilGen.Emit(OpCodes.Box, paramType[i]);//不装箱对一些类型的参数会出错
ilGen.Emit(OpCodes.Stelem_Ref);
}
#endregion
#region 创建MethodContext对象
ConstructorInfo methodContextCI = typeof(MethodContext).GetConstructor(new Type[] { });
ilGen.Emit(OpCodes.Newobj, methodContextCI);
ilGen.Emit(OpCodes.Stloc_2);
ilGen.Emit(OpCodes.Ldloc_2);
#endregion
#region 给MethodInfo付值
ilGen.Emit(OpCodes.Ldloc_0);//MethodInfo
ilGen.EmitCall(OpCodes.Call, typeof(MethodContext).GetMethod("set_MethodInfo", new Type[] { typeof(MethodInfo) }), null);
#endregion
#region 给Executor付值
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder);
ilGen.EmitCall(OpCodes.Call, typeof(MethodContext).GetMethod("set_Executor", new Type[] { typeof(object) }), null);
#endregion
#region 给ParametersValue付值
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Ldloc_1);
ilGen.EmitCall(OpCodes.Call, typeof(MethodContext).GetMethod("set_ParametersValue", new Type[] { typeof(object[]) }), null);
#endregion
#region 创建CallHandler对象并调用方法
Type handlerType = apoAtt.CallHandlerType;
ConstructorInfo ci = handlerType.GetConstructor(new Type[] { });
ilGen.Emit(OpCodes.Newobj, ci);
MethodInfo aopMethod = handlerType.GetMethod("Invoke", new Type[] { typeof(MethodContext) });
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.EmitCall(OpCodes.Call, aopMethod, null);
#endregion
}
else//直接执行原方法
{
#region 将参数压入栈 并执行原方法
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder);
for (int i = 0; i < paramCount; i++)
{
ilGen.Emit(OpCodes.Ldarg, (short)(i + 1));//arg0表示this,真正的方法参数从索引1开始
}
ilGen.EmitCall(OpCodes.Call, targetMethod, null);
#endregion
}
ilGen.Emit(OpCodes.Ret);
}
returnObj = (T)Activator.CreateInstance(typeBuilder.CreateType());
if (returnObj != null)
_Cache[key] = returnObj;
assyBuilder.Save("adcdefg.dll");
}
else
{
returnObj = (T)aopObject;
}
if (returnObj != null)
{
FieldInfo fi = returnObj.GetType().GetField("_SourceObj");
fi.SetValue(returnObj, sourceObj);
}
return returnObj;
}
}
}
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace SimpleAOP
{
public class Wraper
{
private static IDictionary<string, object> _Cache = new Dictionary<string, object>();
public static T Wrap<T>(T sourceObj)
{
T returnObj;
string key = sourceObj.GetType().ToString() + "_" + typeof(T).ToString();
object aopObject;
if (!_Cache.TryGetValue(key, out aopObject))
{
Type returnType = typeof(T);
Type sourceType = sourceObj.GetType();
AppDomain currentAppDomain = AppDomain.CurrentDomain;
AssemblyName assyName = new AssemblyName(sourceType.Name + "_Aop_Assmely");
AssemblyBuilder assyBuilder = currentAppDomain.DefineDynamicAssembly(assyName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder modBuilder = assyBuilder.DefineDynamicModule(sourceType.Name + "_Aop_Module");
String newTypeName = sourceType.Name + "_Aop";
TypeAttributes newTypeAttribute = TypeAttributes.Class | TypeAttributes.Public;
Type newTypeParent;
Type[] newTypeInterfaces;
MethodAttributes methodAttributes = MethodAttributes.Public | MethodAttributes.Virtual;
if (returnType.IsInterface)
{
newTypeParent = null;
newTypeInterfaces = new Type[] { returnType };
}
else
{
newTypeParent = returnType;
newTypeInterfaces = new Type[0];
}
TypeBuilder typeBuilder = modBuilder.DefineType(newTypeName, newTypeAttribute, newTypeParent, newTypeInterfaces);
//创建字段
FieldBuilder fbuilder = typeBuilder.DefineField("_SourceObj", typeof(T), FieldAttributes.Public);
#region 创建构造函数
//ConstructorBuilder conBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(T) });
//ILGenerator conIlGen = conBuilder.GetILGenerator();
//conIlGen.Emit(OpCodes.Ldarg_0);
//conIlGen.Emit(OpCodes.Ldarg_1);
//conIlGen.Emit(OpCodes.Stfld, fbuilder);
//conIlGen.Emit(OpCodes.Ret);
#endregion
MethodInfo[] targetMethods = returnType.GetMethods();
foreach (MethodInfo targetMethod in targetMethods)
{
if ((!targetMethod.IsAbstract) &&(!targetMethod.IsVirtual))
{
continue;
}
#region 得到方法的各个参数的类型
ParameterInfo[] arrParamInfo = targetMethod.GetParameters();
int paramCount = arrParamInfo.Length;
Type[] paramType = new Type[paramCount];
for (int i = 0; i < paramCount; i++)
paramType[i] = arrParamInfo[i].ParameterType;
#endregion
#region 传入方法签名,得到方法生成器
MethodBuilder methodBuilder = typeBuilder.DefineMethod(targetMethod.Name, methodAttributes, targetMethod.ReturnType, paramType);
MethodInfo getTypeMI = typeof(object).GetMethod("GetType", new Type[] { });
MethodInfo getMethodMI = typeof(Type).GetMethod("GetMethod", new Type[] { typeof(string), typeof(Type[]) });
#endregion
#region 定义局部变量
//得到IL生成器
ILGenerator ilGen = methodBuilder.GetILGenerator();
ilGen.DeclareLocal(typeof(MethodInfo), true); //loc0
ilGen.DeclareLocal(typeof(object[]), true);//loc1
ilGen.DeclareLocal(typeof(MethodContext), true);//loc2
ilGen.DeclareLocal(typeof(Type[]), true);//loc3
ilGen.DeclareLocal(typeof(Type), true);//loc4
#endregion
object[] aopAtts = sourceType.GetMethod(targetMethod.Name, paramType).GetCustomAttributes(typeof(SimpleAOP.Attributes.BaseAttribute), true);
if (aopAtts != null && aopAtts.Length > 0)//检测是否标注了AOP属性
{
Attributes.BaseAttribute apoAtt = (Attributes.BaseAttribute)aopAtts[0];
#region 获取sourceObj中的当前MethodInfo并存入loc0中
ilGen.Emit(OpCodes.Nop);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder);
ilGen.EmitCall(OpCodes.Call, getTypeMI, null);
ilGen.Emit(OpCodes.Stloc, 4);
#region 获取参数类型数组
ilGen.Emit(OpCodes.Ldc_I4, paramCount);
ilGen.Emit(OpCodes.Newarr, typeof(Type));
ilGen.Emit(OpCodes.Stloc_3);
ilGen.Emit(OpCodes.Ldloc_3);
for (int i = 0; i < paramCount; i++)
{
ilGen.Emit(OpCodes.Ldc_I4, i);
ilGen.Emit(OpCodes.Ldarg, (short)(i + 1));//arg0表示this,真正的方法参数从索引1开始
ilGen.Emit(OpCodes.Box, paramType[i]);//不装箱对一些类型的参数会出错
ilGen.EmitCall(OpCodes.Call, getTypeMI, null);
ilGen.Emit(OpCodes.Stelem_Ref);
}
#endregion
ilGen.Emit(OpCodes.Ldloc, 4);
ilGen.Emit(OpCodes.Ldstr, targetMethod.Name);
ilGen.Emit(OpCodes.Ldloc_3);
ilGen.EmitCall(OpCodes.Call, getMethodMI, null);
ilGen.Emit(OpCodes.Stloc_0);
#endregion
#region 获取参数并将其存入object[]类型变量loc1中
ilGen.Emit(OpCodes.Ldc_I4, paramCount);
ilGen.Emit(OpCodes.Newarr, typeof(object));
ilGen.Emit(OpCodes.Stloc_1);
ilGen.Emit(OpCodes.Ldloc_1);
for (int i = 0; i < paramCount; i++)
{
ilGen.Emit(OpCodes.Ldc_I4, i);
ilGen.Emit(OpCodes.Ldarg, (short)(i + 1));//arg0表示this,真正的方法参数从索引1开始
ilGen.Emit(OpCodes.Box, paramType[i]);//不装箱对一些类型的参数会出错
ilGen.Emit(OpCodes.Stelem_Ref);
}
#endregion
#region 创建MethodContext对象
ConstructorInfo methodContextCI = typeof(MethodContext).GetConstructor(new Type[] { });
ilGen.Emit(OpCodes.Newobj, methodContextCI);
ilGen.Emit(OpCodes.Stloc_2);
ilGen.Emit(OpCodes.Ldloc_2);
#endregion
#region 给MethodInfo付值
ilGen.Emit(OpCodes.Ldloc_0);//MethodInfo
ilGen.EmitCall(OpCodes.Call, typeof(MethodContext).GetMethod("set_MethodInfo", new Type[] { typeof(MethodInfo) }), null);
#endregion
#region 给Executor付值
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder);
ilGen.EmitCall(OpCodes.Call, typeof(MethodContext).GetMethod("set_Executor", new Type[] { typeof(object) }), null);
#endregion
#region 给ParametersValue付值
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.Emit(OpCodes.Ldloc_1);
ilGen.EmitCall(OpCodes.Call, typeof(MethodContext).GetMethod("set_ParametersValue", new Type[] { typeof(object[]) }), null);
#endregion
#region 创建CallHandler对象并调用方法
Type handlerType = apoAtt.CallHandlerType;
ConstructorInfo ci = handlerType.GetConstructor(new Type[] { });
ilGen.Emit(OpCodes.Newobj, ci);
MethodInfo aopMethod = handlerType.GetMethod("Invoke", new Type[] { typeof(MethodContext) });
ilGen.Emit(OpCodes.Ldloc_2);
ilGen.EmitCall(OpCodes.Call, aopMethod, null);
#endregion
}
else//直接执行原方法
{
#region 将参数压入栈 并执行原方法
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldfld, fbuilder);
for (int i = 0; i < paramCount; i++)
{
ilGen.Emit(OpCodes.Ldarg, (short)(i + 1));//arg0表示this,真正的方法参数从索引1开始
}
ilGen.EmitCall(OpCodes.Call, targetMethod, null);
#endregion
}
ilGen.Emit(OpCodes.Ret);
}
returnObj = (T)Activator.CreateInstance(typeBuilder.CreateType());
if (returnObj != null)
_Cache[key] = returnObj;
assyBuilder.Save("adcdefg.dll");
}
else
{
returnObj = (T)aopObject;
}
if (returnObj != null)
{
FieldInfo fi = returnObj.GetType().GetField("_SourceObj");
fi.SetValue(returnObj, sourceObj);
}
return returnObj;
}
}
}
Wraper中使用Emit首先在代理中生成一个T类型的公有字段用来存放原始对象,遍历T类型中的所有虚方法(接口方法都是虚方法),对标有BaseAttribute类型属性的方法进行实现或者重写,在实现或重写中首先创建MethodContext,然后获取CallHandlerType并创建CallHandler对象,最后调用CallHandler对象的Invoke方法,CallHandler对象中调用MethodContext对象中的Invoke方法调用原方法, 至此我成功拦截执行方法。
使用:
我们用Cahce进行举例说明,首先创建一个类CacheAttribute继承BaseAttribute,代码如下:
CacheAttribute
namespace Example.AOP
{
public class CacheAttribute:SimpleAOP.Attributes.BaseAttribute
{
public override Type CallHandlerType
{
get
{
return typeof(CacheCallHandler);
}
protected set
{
throw new NotImplementedException();
}
}
}
}
namespace Example.AOP
{
public class CacheAttribute:SimpleAOP.Attributes.BaseAttribute
{
public override Type CallHandlerType
{
get
{
return typeof(CacheCallHandler);
}
protected set
{
throw new NotImplementedException();
}
}
}
}
新建一个类CacheCallHandler继承实现ICallHandler 代码如下:
CacheCallHandler
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Example.AOP
{
public class CacheCallHandler:SimpleAOP.ICallHandler
{
private static IDictionary<string, object> _Cache = new Dictionary<string, object>();
#region ICallHandler 成员
public object Invoke(SimpleAOP.MethodContext method)
{
object obj;
StringBuilder key = new StringBuilder(method.MethodInfo.ToString()+"#");
Array.ForEach(method.ParametersValue, p => key.Append(p.ToString() + "_"));
if (!_Cache.TryGetValue(key.ToString(), out obj))
{
obj = method.Invoke();
if (obj != null)
_Cache[key.ToString()] = obj;
}
return obj;
}
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Example.AOP
{
public class CacheCallHandler:SimpleAOP.ICallHandler
{
private static IDictionary<string, object> _Cache = new Dictionary<string, object>();
#region ICallHandler 成员
public object Invoke(SimpleAOP.MethodContext method)
{
object obj;
StringBuilder key = new StringBuilder(method.MethodInfo.ToString()+"#");
Array.ForEach(method.ParametersValue, p => key.Append(p.ToString() + "_"));
if (!_Cache.TryGetValue(key.ToString(), out obj))
{
obj = method.Invoke();
if (obj != null)
_Cache[key.ToString()] = obj;
}
return obj;
}
#endregion
}
}