首页 > 代码库 > 日志系统实战(一)-AOP静态注入
日志系统实战(一)-AOP静态注入
背景
近期在写日志系统,需要在运行时在函数内注入日志记录,并附带函数信息。这时候就想到用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";}
补充:
本文侧重的是核心实现思路。
日志系统实战(一)-AOP静态注入
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。