C#动态代理实现AOP

原创 2018年04月15日 11:55:07

C#实现动态aop比较麻烦,需要用到IL中间语言的知识,笔者最近也在研究,在这记录和分享一下核心方法的解读,本人才疏学浅,如果错误还请指出

        /// <summary>
        /// 创建动态代理方法
        /// </summary>
        /// <param name="typeBuilder">类型构造器</param>
        /// <param name="method">方法元数据</param>
        /// <param name="realObjectField">实际对象</param>
        /// <param name="aspectFields">切面</param>
        private static void EmitMethod(TypeBuilder typeBuilder, MethodInfo method, FieldBuilder realObjectField, List<AspectField> aspectFields)
        {
            //参数列表
            var parameters = method.GetParameters();
            //动态实例
            var emitter = Sigil.NonGeneric.Emit.BuildInstanceMethod(method.ReturnType, parameters.Select(i => i.ParameterType).ToArray(), typeBuilder, method.Name, MethodAttributes.Public | MethodAttributes.Virtual);

            //label base
            var lbCallBase = emitter.DefineLabel();
            //label return
            var lbReturn = emitter.DefineLabel();

            //方法上下文
            var methodContextLocal = emitter.DeclareLocal(typeof(MethodContext));
            //返回
            var returnLocal = method.ReturnType != typeof(void) ? emitter.DeclareLocal(method.ReturnType) : null;
            //本地存储
            var objArrayLocal = emitter.DeclareLocal(typeof(object[]));
            //异常
            var exceptionLocal = emitter.DeclareLocal<Exception>();
            //切面列表
            var aspects = method.GetCustomAttributes(typeof(AspectAttribute), false).Cast<AspectAttribute>().Concat(AspectFactory.GlobalAspects).ToList();
            //是否包含异常切面
            bool hasException = aspects.Any(i => i.GetType().GetMethod("ExceptionFilter").DeclaringType != typeof(AspectAttribute));
            //异常捕捉块
            Sigil.ExceptionBlock tryBlock = null;
            //方法名
            string methodName = method.Name;
            if (aspects.Any())
            {
                //给参数分配内存
                emitter
                    .LoadConstant(parameters.Length)
                    .NewArray<object>()
                    .StoreLocal(objArrayLocal); // var parameters = new object[parameters.Length];

                //给参数填充实际值
                for (int i = 0; i < parameters.Length; i++)
                {
                    emitter
                        .LoadLocal(objArrayLocal)
                        .LoadConstant(i)
                        .LoadArgument((ushort)(i + 1))
                        .Box(parameters[i].ParameterType, true)
                        .StoreElement<object>(); // parameters[i] = paramN;
                }

                //通过使用该方法的内部元数据表示形式 (句柄) 获取方法的信息
                emitter
                     .LoadConstant(method)
                     .Call(typeof(MethodBase).GetMethod("GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle) }))
                     .CastClass<MethodInfo>() // methodof(Method)

                    //加载真实方法对象
                     .LoadArgument(0)
                     .LoadField(realObjectField) // this.realObject

                    //加载自定义的上下文
                     .LoadLocal(objArrayLocal)
                     .Call(typeof(ProxyBase).GetMethod("GetMethodContext", BindingFlags.Static | BindingFlags.NonPublic))
                     .StoreLocal(methodContextLocal); // methodContextLocal = GetMethodContext(methodof(Method), this.realObject, parameters
            }

            var currentMethodAspects = new List<AspectField>();
            //根据切面的优先级排序
            foreach (var aspect in aspects.OrderBy(i => i.EnterPriority))
            {
                //创建切面
                var field = typeBuilder.DefineField("aspectField_" + Guid.NewGuid(), typeof(AspectAttribute), FieldAttributes.Static | FieldAttributes.Private);
                aspectFields.Add(new AspectField { Aspect = aspect, Field = field });
                currentMethodAspects.Add(new AspectField { Aspect = aspect, Field = field });

                //调用切面前处理
                emitter
                    .LoadField(field)
                    .LoadLocal(methodContextLocal)
                    .CallVirtual(typeof(AspectAttribute).GetMethod(GetName(aspect.MethodEnter), BindingFlags.Instance | BindingFlags.Public));

                //如果方法有返回则试图获取 返回值  返回如果不为空则标志lbreturn 直接返回结束
                if (method.ReturnType != typeof(void))
                {
                    emitter
                        .LoadLocal(methodContextLocal)
                        .Call(typeof(MethodContext).GetProperty("ReturnValue").GetGetMethod())
                        .BranchIfTrue(lbReturn);
                }
            }

            //Chama o método base 标记调用父方法
            emitter.MarkLabel(lbCallBase);

            //如果包含异常捕捉切面则添加一个trycatch块
            if (hasException)
                tryBlock = emitter.BeginExceptionBlock();

            if (aspects.Any() && method.ReturnType != typeof(void))  //Armazena o objeto retornado no ReturnValue caso haja aspectos
                emitter.LoadLocal(methodContextLocal);

            emitter
                .LoadArgument(0)
                .LoadField(realObjectField);
            for (int i = 0; i < parameters.Length; i++)
                emitter.LoadArgument((ushort)(i + 1));
            //调用实际的方法
            emitter.CallVirtual(method); //realObject.Method(parameters...);
            //保存返回值
            if (method.ReturnType != typeof(void))
                emitter.StoreLocal(returnLocal);


            //Armazena o objeto retornado no ReturnValue caso haja aspectos
            //设置methodcontext里的返回值
            if (method.ReturnType != typeof(void) && aspects.Any())
            {
                emitter
                    .LoadLocal(returnLocal)
                    .Box(method.ReturnType, true)
                    .Call(typeof(MethodContext).GetProperty("ReturnValue").GetSetMethod());
            }

            //开始调用切面里面的异常处理
            if (hasException)
            {
                var catchBlock = emitter.BeginCatchBlock<Exception>(tryBlock);
                emitter.StoreLocal(exceptionLocal);

                foreach (var aspect in currentMethodAspects.Where(i => i.Aspect.GetType().GetMethod("ExceptionFilter").DeclaringType != typeof(AspectAttribute)))
                    emitter
                        .LoadField(aspect.Field)
                        .LoadLocal(methodContextLocal)
                        .LoadLocal(exceptionLocal)
                        .CallVirtual(typeof(AspectAttribute).GetMethod("ExceptionFilter", BindingFlags.Instance | BindingFlags.Public));
                //切面异常处理结束之后重新抛出异常  不影响后续流程
                emitter
                    .ReThrow()
                    .EndCatchBlock(catchBlock)
                    .EndExceptionBlock(tryBlock);
            }

            //循环按照优先级调用切面后处理
            emitter.MarkLabel(lbReturn);
            foreach (var aspect in currentMethodAspects.OrderBy(i => i.Aspect.ExitPriority))
            {
                emitter
                    .LoadField(aspect.Field)
                    .LoadLocal(methodContextLocal)
                    .CallVirtual(typeof(AspectAttribute).GetMethod(GetName(aspect.Aspect.MethodExit), BindingFlags.Instance | BindingFlags.Public));
            }
            //存储返回值
            if (method.ReturnType != typeof(void))
            {
                if (aspects.Any())
                {
                    emitter
                        .LoadLocal(methodContextLocal)
                        .Call(typeof(MethodContext).GetProperty("ReturnValue").GetGetMethod())
                        .UnboxAny(method.ReturnType, true)
                        .StoreLocal(returnLocal);

                }

                if (method.ReturnType != typeof(void))
                    emitter.LoadLocal(returnLocal);
            }
            //返回
            emitter.Return();
            //生成代理方法
            var newMethod = emitter.CreateMethod();
            typeBuilder.DefineMethodOverride(newMethod, method);
        }

动态代理实现AOP机制

  • 2011年10月28日 20:24
  • 11.55MB
  • 下载

AOP实现原理——动态代理

前几天阿里面试问AOP是怎么实现的,感觉自己当时答的不好,于是回来重新研究了一下,找了下资料,现在来做个分享.       Spring两大核心IOC与AOP.IOC负责将对象动态的注入到容器,让容...
  • KevinDai007
  • KevinDai007
  • 2016-03-31 17:52:50
  • 1462

AOP的简单实现---动态代理机制

动态代理:动态代理顾名思义就是代理目标对象处理某些事情 正向代理:可以理解成火车售卖点就是中国铁路总公司的代理,我们把买票的业务委托给火车票售卖点,售卖点通过软件等形式替我们向铁总买票,然后再将...
  • yang1464657625
  • yang1464657625
  • 2016-12-20 11:51:53
  • 605

AOP的实现原理—反射与动态代理

其实AOP的意思就是面向切面编程。OO注重的是我们解决问题的方法(封装成Method),而AOP注重的是许多解决解决问题的方法中的共同点,是对OO思想的一种补充!还是拿人家经常举的一个例子讲解一下吧:...
  • fuzhongmin05
  • fuzhongmin05
  • 2017-03-12 11:01:39
  • 1296

Spring AOP的实现——动态代理机制

在java的动态代理中,有两个重要的类或者接口,一个是InvocationHandler(Interface)、另一个是Proxy(Class),这一个类和接口是实现动态代理所必须的。 Invocat...
  • bingogirl
  • bingogirl
  • 2016-08-29 21:15:05
  • 10246

AOP源码解析(一)实现动态代理

动态AOP使用示例 面向对象编程有一些弊端,当需要为多个不具有继承关系的对象引入同一个公共行为时,例如日志,安全检测等,我们只有在每个对象里引入公共行为,这样程序中就产生了大量的重复代码,所以有了面...
  • u012291108
  • u012291108
  • 2016-10-30 23:27:49
  • 1480

AOP之静态代理VS动态代理

一、代理概念         为某个对象提供一个代理,以控制对这个对象的访问。代理类和委托类有共同的父类或父接口,代理类负责请求的预处理,过滤,将请求分配给委托类处理。 二、静态代理:        ...
  • u010097777
  • u010097777
  • 2016-06-06 21:37:02
  • 2285

Spring AOP中的动态代理实现机制

AOP中的目标对象(target object),也被称为是advised object,是在pointcut处插入aspect时所执行的advice方法中所用到的对象。有点罗嗦,请慢慢体会。任何一个...
  • taiyangdao
  • taiyangdao
  • 2016-04-23 17:41:57
  • 487

spring实现AOP的两种方式以及实现动态代理方式

AOP: 方式一:Annatation 注解方式 1、spring依赖库  * SPRING_HOME/dist/spring.jar  * SPRING_HOME/lib/jakar...
  • shangzhiliang_2008
  • shangzhiliang_2008
  • 2015-08-30 11:30:24
  • 2771

AOP动态代理的简单实现

众所周知,java是面向对象语言的有力代表,提到java我们就会立即想到面向对象,提到面向对象我们就会想到java。然而面向对象也并非完美无缺的,它更注重于对象层次结构方面的东西,对于如何更好的管理对...
  • dengken53
  • dengken53
  • 2017-01-24 14:13:54
  • 182
收藏助手
不良信息举报
您举报文章:C#动态代理实现AOP
举报原因:
原因补充:

(最多只允许输入30个字)