首页 > 学院 > 开发设计 > 正文

大家一起Aop

2019-11-17 03:20:20
字体:
来源:转载
供稿:网友

大家一起Aop

一、前言

  1.在项目中无处不充斥着记录日志的代码,各种try catch,实在是有点看着不爽。这不,果断要想法子偷个懒儿。

二、摘要

鄙人不才,先总结一下个人想到的可实现AOP的几种思路:

  1.通过继承特定实例,重写虚方法(C#中如virtual、override方法),动态构建一个该实例的子类,进行调用。

  2.通过实现特定实例上的接口,动态构建一个该接口的实现类,切入AOP代码,内部包裹特定实例的方法。

  3.最简单的一种方式,通过给特定实例继承MarshalByRefObject类,并且用继承RealPRoxy的代理类进行构造包裹。

代码比较少,有些Emit基础的童鞋应该很容易看懂,接下去直接上核心代码。

三、继承类模式

  1 if (!method.IsPublic || !method.IsVirtual/*非虚方法无法重写*/|| method.IsFinal /*Final方法无法重写,如interface的实现方法标记为 virtual final*/ || IsObjectMethod(method)) return;  2   3             const MethodAttributes methodattributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual;  4             Type[] paramTypes = method.GetParameters().Select(ent => ent.ParameterType).ToArray();  5             MethodBuilder mb = _typeBuilder.DefineMethod(method.Name, methodattributes, method.ReturnType, paramTypes);  6             ILGenerator il = mb.GetILGenerator();  7   8             #region 初始化本地变量和返回值  9             //加载所有参数到本地object[],实例方法第一个参数是this,已排除 10             LoadArgsIntoLocalField(il, paramTypes); 11  12             //如果有返回值,定义返回值变量 13             bool isReturnVoid = method.ReturnType == typeof(void); 14             LocalBuilder result = null; 15             if (!isReturnVoid) 16                 result = il.DeclareLocal(method.ReturnType); 17  18             //定义MethodInfo变量,下面会用到(传递到Aop的上下文中) 19             var methodInfo = il.DeclareLocal(typeof(MethodBase)); 20             il.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetCurrentMethod", Type.EmptyTypes)); 21             il.Emit(OpCodes.Stloc, methodInfo); 22             #endregion 23  24             #region 初始化aspectContext 25             Type contextType = typeof(AspectContext); 26             var context = il.DeclareLocal(contextType); 27             ConstructorInfo info = contextType.GetConstructor(Type.EmptyTypes); 28             il.Emit(OpCodes.Newobj, info); 29             il.Emit(OpCodes.Stloc, context); 30             #endregion 31  32             #region 给AspectContext的参数值属性ParameterArgs,MethodInfo赋值 33             il.Emit(OpCodes.Ldloc, context); 34             il.Emit(OpCodes.Ldloc_0); 35             il.Emit(OpCodes.Call, contextType.GetMethod("set_ParameterArgs")); 36  37             il.Emit(OpCodes.Ldloc, context); 38             il.Emit(OpCodes.Ldloc, methodInfo); 39             il.Emit(OpCodes.Call, contextType.GetMethod("set_MethodInfo")); 40             #endregion 41  42             AspectAttribute[] attrs = GetAspectAttributes(method); 43             int attrLen = attrs.Length; 44             LocalBuilder[] lbs = new LocalBuilder[attrLen]; 45             MethodInfo[] endInvokeMethods = new MethodInfo[attrLen]; 46             MethodInfo[] invokingExceptionMethods = new MethodInfo[attrLen]; 47  48             #region 初始化标记的切面对象,并调用切面对象的BeforeInvoke方法 49             for (int i = 0; i < attrLen; i++) 50             { 51                 var tmpAttrType = attrs[i].GetType(); 52                 var tmpAttr = il.DeclareLocal(tmpAttrType); 53                 ConstructorInfo tmpAttrCtor = tmpAttrType.GetConstructor(Type.EmptyTypes); 54  55                 il.Emit(OpCodes.Newobj, tmpAttrCtor); 56                 il.Emit(OpCodes.Stloc, tmpAttr); 57  58                 var beforeInvokeMethod = tmpAttrType.GetMethod("BeforeInvoke"); 59                 endInvokeMethods[i] = tmpAttrType.GetMethod("AfterInvoke"); 60                 invokingExceptionMethods[i] = tmpAttrType.GetMethod("InvokingException"); 61  62                 il.Emit(OpCodes.Ldloc, tmpAttr); 63                 il.Emit(OpCodes.Ldloc, context); 64                 il.Emit(OpCodes.Callvirt, beforeInvokeMethod); 65                 il.Emit(OpCodes.Nop); 66  67                 lbs[i] = tmpAttr; 68             } 69             #endregion 70  71             //try 72             il.BeginExceptionBlock(); 73  74             #region 调用实现方法 75             if (!method.IsAbstract) 76             { 77                 //类对象,参数值依次入栈 78                 for (int i = 0; i <= paramTypes.Length; i++) 79                     il.Emit(OpCodes.Ldarg, i); 80  81                 //调用基类的方法 82                 il.Emit(OpCodes.Call, method); 83  84                 if (!isReturnVoid) 85                 { 86                     il.Emit(OpCodes.Stloc, result); 87  88                     // 89                     il.Emit(OpCodes.Ldloc, context); 90                     il.Emit(OpCodes.Ldloc, result); 91                     if (method.ReturnType.IsValueType) 92                         il.Emit(OpCodes.Box, method.ReturnType); 93                     il.Emit(OpCodes.Call, contextType.GetMethod("set_ReturnObj")); 94                 } 95             } 96             #endregion 97  98             //catch 99             il.BeginCatchBlock(typeof(Exception));100             var exception = il.DeclareLocal(typeof(Exception));101             il.Emit(OpCodes.Stloc, exception);102 103             #region 初始化ExceptionContext104             var exceptionContentType = typeof(ExceptionContext);105             var exceptionContent = il.DeclareLocal(exceptionContentType);106             var exceptionContentCtor = exceptionContentType.GetConstructor(Type.EmptyTypes);107             il.Emit(OpCodes.Newobj, exceptionContentCtor);108             il.Emit(OpCodes.Stloc, exceptionContent);109             #endregion110 111             #region 给ExceptionContext的参数值属性ParameterArgs,MethodInfo,ExceptionInfo,赋值112             il.Emit(OpCodes.Ldloc, exceptionContent);113             il.Emit(OpCodes.Ldloc_0);114             il.Emit(OpCodes.Call, exceptionContentType.GetMethod("set_ParameterArgs"));115 116             il.Emit(OpCodes.Ldloc, exceptionContent);117             il.Emit(OpCodes.Ldloc, methodInfo);118             il.Emit(OpCodes.Call, exceptionContentType.GetMethod("set_MethodInfo"));119 120             il.Emit(OpCodes.Ldloc, exceptionContent);121             il.Emit(OpCodes.Ldloc, exception);122             il.Emit(OpCodes.Call, exceptionContentType.GetMethod("set_ExceptionInfo"));123             #endregion124 125             #region 调用切面对象的InvokingException方法126             for (int i = 0; i < attrLen; i++)127             {128                 il.Emit(OpCodes.Ldloc, lbs[i]);129                 il.Emit(OpCodes.Ldloc, exceptionContent);130                 il.Emit(OpCodes.Callvirt, invokingExceptionMethods[i]);131                 il.Emit(OpCodes.Nop);132             }133             #endregion134             //try end135             il.EndExceptionBlock();136 137             #region 调用切面对象的AfterInvoke方法138             for (int i = 0; i < attrLen; i++)139             {140                 il.Emit(OpCodes.Ldloc, lbs[i]);141                 il.Emit(OpCodes.Ldloc, context);142                 il.Emit(OpCodes.Callvirt, endInvokeMethods[i]);143                 il.Emit(OpCodes.Nop);144             }145             #endregion146 147             if (!isReturnVoid)148                 il.Emit(OpCodes.Ldloc, result);149 150             //返回151             il.Emit(OpCodes.Ret);
继承类模式

该种方式,建立在使用base.XXXMethod(arg1,arg2,...)模式来调用被Aop的对象的业务方法,关键点是使用BeginExceptionBlock(),BeginCatchBlock(typeof(Exception)),EndExceptionBlock();来动态创建try catch代码块,进行异常处理。

四、实现接口模式

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表