转载

AOP编程之动态代理

关于静态代理请参考:

http://www.hechunbo.com/index.php/archives/209.html

动态代理 的特点是程序自动生成代理类,不用再根据业务来一个一个类写了。

是运行时代理。

创建Action特性,标记于方法上

/// <summary>
/// 标记方法特性,在调用类中的方法时,调用before
/// </summary>
public class ActionAttribute : ActionBaseAttribute
    {
        public override void Before(string @method, object[] parameters)
        {
            Console.WriteLine("ActionAttribute before,method:" + method);
        }
        public override object After(string @method, object result)
        {
            Console.WriteLine(" ActionAttribute after,method:" + method);
            return base.After(method, result);
        }
    }

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class ActionBaseAttribute : Attribute
    {
        public virtual void Before(string @method, object[] parameters) { }

        public virtual object After(string @method, object result) { return result; }
    }

创建Interceptor特性,标记于类

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class InterceptorBaseAttribute : Attribute
    {
        public virtual object Invoke(object @object, string @method, object[] parameters)
        {
            return @object.GetType().GetMethod(@method).Invoke(@object, parameters);
        }
    }

    /// <summary>
    /// 定义类的特性。也是在方法前后调用 ,但是先办理出action日志 。因为action特性标记在方法上。
    /// </summary>
    public class InterceptorAttribute : InterceptorBaseAttribute
    {
        public override object Invoke(object @object, string @method, object[] parameters)
        {
            Console.WriteLine("InterceptorAttribute before invokc");
            object obj = null;
            try
            {
                obj = base.Invoke(@object, method, parameters);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.WriteLine("InterceptorAttribute after invoke");
            return obj;
        }
    }

    public interface IBusinessClass
    {
        void add();
    }

业务类和业务接口

public interface IBusinessClass
    {
        void add();
    }

    [Interceptor]
    public class Business : IBusinessClass
    {
        [Action]
        public void add()
        {
            Console.WriteLine("add method");
        }
    }

用Emit生成的动态代理类的IL

public class DynamicProxy
    {
        public static TInterface CreateProxyOfRealize<TInterface, TImp>()
            where TImp : class, new()
            where TInterface : class
        {
            return Invoke<TInterface, TImp>();
        }

        public static TProxyClass CreateProxyOfInherit<TProxyClass>() where TProxyClass : class, new()
        {
            return Invoke<TProxyClass, TProxyClass>(true);
        }

        private static TInterface Invoke<TInterface, TImp>(bool inheritMode = false)
            where TImp : class, new()
            where TInterface : class
        {
            var impType = typeof (TImp);

            string nameOfAssembly = impType.Name + "ProxyAssembly";
            string nameOfModule = impType.Name + "ProxyModule";
            string nameOfType = impType.Name + "Proxy";
            var assemblyName = new AssemblyName(nameOfAssembly);
            var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
            var moduleBuilder = assembly.DefineDynamicModule(nameOfModule);

            //var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            //var moduleBuilder = assembly.DefineDynamicModule(nameOfModule, nameOfAssembly + ".dll");

            TypeBuilder typeBuilder;
            if (inheritMode)
                typeBuilder = moduleBuilder.DefineType(nameOfType, TypeAttributes.Public, impType);
            else
                typeBuilder = moduleBuilder.DefineType(nameOfType, TypeAttributes.Public, null,
                    new[] {typeof (TInterface)});

            InjectInterceptor<TImp>(typeBuilder, impType.GetCustomAttribute(typeof (InterceptorBaseAttribute)).GetType(),inheritMode);

            var t = typeBuilder.CreateType();

            //assembly.Save(nameOfAssembly + ".dll");

            return Activator.CreateInstance(t) as TInterface;
        }

        private static void InjectInterceptor<TImp>(TypeBuilder typeBuilder, Type interceptorAttributeType,bool inheritMode = false)
        {
            var impType = typeof (TImp);
            // ---- define fields ----
            FieldBuilder fieldInterceptor = null;
            if (interceptorAttributeType != null)
            {
                fieldInterceptor = typeBuilder.DefineField("_interceptor", interceptorAttributeType,
                    FieldAttributes.Private);
            }
            // ---- define costructors ----
            if (interceptorAttributeType != null)
            {
                var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public,
                    CallingConventions.Standard, null);
                var ilOfCtor = constructorBuilder.GetILGenerator();

                ilOfCtor.Emit(OpCodes.Ldarg_0);
                ilOfCtor.Emit(OpCodes.Newobj, interceptorAttributeType.GetConstructor(new Type[0]));
                ilOfCtor.Emit(OpCodes.Stfld, fieldInterceptor);
                ilOfCtor.Emit(OpCodes.Ret);
            }

            // ---- define methods ----

            var methodsOfType = impType.GetMethods(BindingFlags.Public | BindingFlags.Instance);

            string[] ignoreMethodName = new[] {"GetType", "ToString", "GetHashCode", "Equals"};

            foreach (var method in methodsOfType)
            {
                //ignore method
                if (ignoreMethodName.Contains(method.Name))
                    return;

                var methodParameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();

                MethodAttributes methodAttributes;

                if (inheritMode)
                    methodAttributes = MethodAttributes.Public | MethodAttributes.Virtual;
                else
                    methodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot |
                                       MethodAttributes.Virtual | MethodAttributes.Final;

                var methodBuilder = typeBuilder.DefineMethod(method.Name, methodAttributes, CallingConventions.Standard,
                    method.ReturnType, methodParameterTypes);

                var ilMethod = methodBuilder.GetILGenerator();

                // set local field
                var impObj = ilMethod.DeclareLocal(impType); //instance of imp object
                var methodName = ilMethod.DeclareLocal(typeof (string)); //instance of method name
                var parameters = ilMethod.DeclareLocal(typeof (object[])); //instance of parameters
                var result = ilMethod.DeclareLocal(typeof (object)); //instance of result
                LocalBuilder actionAttributeObj = null;

                //attribute init
                Type actionAttributeType = null;
                if (method.GetCustomAttribute(typeof (ActionBaseAttribute)) != null ||
                    impType.GetCustomAttribute(typeof (ActionBaseAttribute)) != null)
                {
                    //method can override class attrubute
                    if (method.GetCustomAttribute(typeof (ActionBaseAttribute)) != null)
                    {
                        actionAttributeType = method.GetCustomAttribute(typeof (ActionBaseAttribute)).GetType();
                    }
                    else if (impType.GetCustomAttribute(typeof (ActionBaseAttribute)) != null)
                    {
                        actionAttributeType = impType.GetCustomAttribute(typeof (ActionBaseAttribute)).GetType();
                    }

                    actionAttributeObj = ilMethod.DeclareLocal(actionAttributeType);
                    ilMethod.Emit(OpCodes.Newobj, actionAttributeType.GetConstructor(new Type[0]));
                    ilMethod.Emit(OpCodes.Stloc, actionAttributeObj);
                }

                //instance imp
                ilMethod.Emit(OpCodes.Newobj, impType.GetConstructor(new Type[0]));
                ilMethod.Emit(OpCodes.Stloc, impObj);

                //if no attribute
                if (fieldInterceptor != null || actionAttributeObj != null)
                {
                    ilMethod.Emit(OpCodes.Ldstr, method.Name);
                    ilMethod.Emit(OpCodes.Stloc, methodName);

                    ilMethod.Emit(OpCodes.Ldc_I4, methodParameterTypes.Length);
                    ilMethod.Emit(OpCodes.Newarr, typeof (object));
                    ilMethod.Emit(OpCodes.Stloc, parameters);

                    // build the method parameters
                    for (var j = 0; j < methodParameterTypes.Length; j++)
                    {
                        ilMethod.Emit(OpCodes.Ldloc, parameters);
                        ilMethod.Emit(OpCodes.Ldc_I4, j);
                        ilMethod.Emit(OpCodes.Ldarg, j + 1);
                        //box
                        ilMethod.Emit(OpCodes.Box, methodParameterTypes[j]);
                        ilMethod.Emit(OpCodes.Stelem_Ref);
                    }
                }
                //如果存在action特性,加载实例化对象,参数,执行before方法 
                //dynamic proxy action before
                if (actionAttributeType != null)
                {
                    //load arguments
                    ilMethod.Emit(OpCodes.Ldloc, actionAttributeObj);
                    ilMethod.Emit(OpCodes.Ldloc, methodName);
                    ilMethod.Emit(OpCodes.Ldloc, parameters);
                    ilMethod.Emit(OpCodes.Call, actionAttributeType.GetMethod("Before"));
                }
                //如果存在interceptor特性,调用类字段的invoke方法 
                if (interceptorAttributeType != null)
                {
                    //load arguments
                    ilMethod.Emit(OpCodes.Ldarg_0); //this
                    ilMethod.Emit(OpCodes.Ldfld, fieldInterceptor);
                    ilMethod.Emit(OpCodes.Ldloc, impObj);
                    ilMethod.Emit(OpCodes.Ldloc, methodName);
                    ilMethod.Emit(OpCodes.Ldloc, parameters);
                    // call Invoke() method of Interceptor
                    ilMethod.Emit(OpCodes.Callvirt, interceptorAttributeType.GetMethod("Invoke"));
                }
                else
                {
                    //direct call method
                    if (method.ReturnType == typeof (void) && actionAttributeType == null)
                    {
                        ilMethod.Emit(OpCodes.Ldnull);
                    }

                    ilMethod.Emit(OpCodes.Ldloc, impObj);
                    for (var j = 0; j < methodParameterTypes.Length; j++)
                    {
                        ilMethod.Emit(OpCodes.Ldarg, j + 1);
                    }
                    ilMethod.Emit(OpCodes.Callvirt, impType.GetMethod(method.Name));
                    //box
                    if (actionAttributeType != null)
                    {
                        if (method.ReturnType != typeof (void))
                            ilMethod.Emit(OpCodes.Box, method.ReturnType);
                        else
                            ilMethod.Emit(OpCodes.Ldnull);
                    }
                }
                //如果action特性存在,则把结果包装成object传给after方法 
                //dynamic proxy action after
                if (actionAttributeType != null)
                {
                    ilMethod.Emit(OpCodes.Stloc, result);
                    //load arguments
                    ilMethod.Emit(OpCodes.Ldloc, actionAttributeObj);
                    ilMethod.Emit(OpCodes.Ldloc, methodName);
                    ilMethod.Emit(OpCodes.Ldloc, result);
                    ilMethod.Emit(OpCodes.Call, actionAttributeType.GetMethod("After"));
                }

                
                // pop the stack if return void //void类型,直接返回结果
                if (method.ReturnType == typeof (void))
                {
                    ilMethod.Emit(OpCodes.Pop);
                }
                else
                {
                    //unbox,if direct invoke,no box
                    if (fieldInterceptor != null || actionAttributeObj != null)
                    {
                        if (method.ReturnType.IsValueType)//值类型=拆箱
                            ilMethod.Emit(OpCodes.Unbox_Any, method.ReturnType);
                        else
                            ilMethod.Emit(OpCodes.Castclass, method.ReturnType); //引用类型,则需要类型转换
                    }
                }
                // complete
                ilMethod.Emit(OpCodes.Ret);
            }
        }
    }

方法测试和调用

class Program
    {
        static void Main(string[] args)
        {
            IBusinessClass instance = DynamicProxy.CreateProxyOfRealize<IBusinessClass, Business>();
            instance.add();
            Console.ReadKey();
        }
    }

方法运行结果

先输出action类的before方法 ,再调用Interceptor特性的before方法 。出是先interceptor,后action

==>action方法特性在最外层, Intercepror特性类在最方法的最内层。

ActionAttribute before,method:add
InterceptorAttribute before invokc
add method
InterceptorAttribute after invoke
ActionAttribute after,method:add

参考

AOP从静态代理到动态代理(Emit实现)详解

https://www.jb51.net/article/147526.htm

原文  http://www.hechunbo.com/index.php/archives/210.html
正文到此结束
Loading...