标签:des style blog os io strong for ar div
背景
近期在写日志系统,需要在运行时在函数内注入日志记录,并附带函数信息。这时候就想到用Aop的方式了。
技术分析
AOP分动态注入和静态注入。
动态注入方式
1:Remoting的ContextAttribute上下文(性能差)。
2:动态代理(反射),大多AOP框架都用这种方式。
3:MVC的filter,也是反射。
第一种:性能太差不考虑。第二种:为了记日志,生产环境都用动态代理,性能损耗不小,不推荐。第三种:只有UI层能用。其他层和第二种一样。
静态注入方式 (本文重点)。
1:基于IL注入,损耗可以忽略不计。PostSharp采用的这种方式。
技术实现:
1:声明Attribute
public class WeaveSign:Attribute { } public class WeaveAction : Attribute { } public class Log : WeaveAction { public static void OnActionBefore(MethodBase mbBase) { //mbBase 要注入方法的所有信息 var t = mbBase.GetParameters(); LogManager.Record(); } }
2:标记需要注入的方法
[Log] public static string GetUserName(int userId) { return "Vidar"; }
3:IL注入(关键点),采用Mono.Cecil
private static void Weave(IEnumerable<Assembly> assemblyList) { //assemblyList要注入的程序集列表。 foreach (var item in assemblyList) { var filepath = item.CodeBase.Substring(8, item.CodeBase.Length - 8); //读取程序集 var assembly = AssemblyDefinition.ReadAssembly(filepath); //获取WeaveSign类型的类型注入标记 var types = assembly.MainModule.Types.Where(n => n.CustomAttributes.Any(y => y.AttributeType.Resolve().Name == "WeaveSign")); foreach (var type in types) { foreach (var method in type.Methods) { //获取WeaveAction类型的方法注入标记 var attrs = method.CustomAttributes.Where(y => y.AttributeType.Resolve().BaseType.Name == "WeaveAction"); foreach (var attr in attrs) { //还原类型 var resolve = attr.AttributeType.Resolve(); //获取IL容器 var ilProcessor = method.Body.GetILProcessor(); var firstInstruction = ilProcessor.Body.Instructions.First(); //找到标记类型的OnActionBefore方法。 var onActionBefore = resolve.GetMethods().Single(n => n.Name == "OnActionBefore"); //创建System.Reflection.MethodBase.GetCurrentMethod()方法引用 var mfReference=assembly.MainModule.Import(typeof (System.Reflection.MethodBase).GetMethod("GetCurrentMethod")); //注入到IL(调用GetCurrentMethod,入栈) ilProcessor.InsertBefore(firstInstruction, ilProcessor.Create(OpCodes.Call,mfReference)); //创建调用(call)标记类型的方法OnActionBefore ilProcessor.InsertBefore(firstInstruction, ilProcessor.Create(OpCodes.Call, onActionBefore)); } } } if (types.Any()) { //写入程序集 assembly.Write(filepath); } } }
3:编译成功后。反编译看到如下代码。
IL
.method public hidebysig static string GetUserName(int32 userId) cil managed { .custom instance void TestLibrary.Log::.ctor() .maxstack 1 .locals init ( [0] string str) L_0000: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetCurrentMethod() L_0005: call void TestLibrary.Log::OnActionBefore(class [mscorlib]System.Reflection.MethodBase) L_000a: nop L_000b: ldstr "Vidar" L_0010: stloc.0 L_0011: br.s L_0013 L_0013: ldloc.0 L_0014: ret }
C#
[Log] public static string GetUserName(int userId) { Log.OnActionBefore(MethodBase.GetCurrentMethod()); return "Vidar"; }
补充:
本文侧重的是核心实现思路。
标签:des style blog os io strong for ar div
原文地址:http://www.cnblogs.com/mushroom/p/3932698.html