zoukankan      html  css  js  c++  java
  • .Net中的Interception一个简单的AOP框架学习

    最近翻手头的dll文件时无意中发现了一个Interception实现,这个框架比起目前流行的AOP框架显的比较简漏,但却很好的体现出了.net下AOP是怎么实现的,于是就整理出来。

    在.Net Unity2.0中的Interception,按三种方式实现:

    1.TransparentProxy/RealProxy Interceptor 即Remoting代理机制。

    2.Interface Interceptor  即动态代码 (Emit编程)实现

    3.Virtual Method Interceptor 也是动态代码实现,Emit编程基本类似于IL编程了。

    需要注意的是使用VirtuatMethodInterceptor后,PolicyInjectionBehavior会被忽略,通过Resovle获取的始终是继承被拦截类的子类实例
    而透明代理与接口方式在全部移除匹配策略后(Policy,就是这个类不需要拦截了),Resolve返回的是原始类(非代理类)

    实例拦截与类型拦截

    1.实例拦截

     

    TransparentProxy 与 Interface Interceptor 属于实例拦截,所谓实例拦截就是被拦截对象完整而独立的在内参中存在。Client端通过代理类与被拦截对象发生通信(方法调用)。

    2.类型拦截

    Virtual Method 方式属于类型拦截,内参中不存在被拦截类型的实例,拦截框架通过动态代码生成被拦截类型的子类型程序集,该程序集被加载后对应的子类型被实例化于内存中与Client发生通信

     

    下面针对TransparentProxy/RealProxy 与 Interface Interceptor帖出手头上dll实现的代码

    1.TransparentProxy/RealProxy实现

        using System.Reflection;
        using System.Runtime.Remoting.Proxies;
        using System.Runtime.Remoting.Messaging;
        using System.Runtime.Remoting;
    
    
        internal class TransparentProxy : RealProxy
        {
            // Fields
            private readonly MarshalByRefObject m_Target;
    
            // Methods
            public TransparentProxy(MarshalByRefObject target)
                : base(target.GetType())
            {
                this.m_Target = target;
            }
    
            public static object GetProxy(MarshalByRefObject target)
            {
                TransparentProxy proxy = new TransparentProxy(target);
                return proxy.GetTransparentProxy();
            }
    
            public override IMessage Invoke(IMessage msg)
            {
                IMessage message = null;
                IMethodCallMessage callMsg = msg as IMethodCallMessage;
                if (callMsg != null)
                {
                    object[] customAttributes = callMsg.MethodBase.GetCustomAttributes(true);
                    this.InvokeBeforeAttribute(customAttributes, callMsg);
                    try
                    {
                        message = RemotingServices.ExecuteMessage(this.m_Target, callMsg);
                    }
                    catch (Exception exception)
                    {
                        this.InvokeExceptionAttribute(customAttributes, callMsg, exception);
                        throw;
                    }
                    this.InvokeAfterAttribute(customAttributes, callMsg, ((ReturnMessage)message).ReturnValue);
                }
                return message;
            }
          //..........
          //............
        }
    

    类TransproxyProxy中维护着一个到target类实例的引用(必须是MarshalByRefObject类型的子类),最终的方法调用会通过消息机制到达target实例--语句RemotingServices.ExecuteMessage(this.m_Target, callMsg);,在调用目标对象的目标方法之前会调用InvokeBeforeAttribute,错误时会调用InvokeExceptionAttribute,而完成后调用InvokeAfterAttribute.这里需要注意的是Unity2.0 Interception 中将要调用的InterceptionBehavior构建成管道模型,编程时会有Scop样的开闭结构,而这里的实现只是顺序的调用,这点需要加以区分。InvokeBeforeAttribute等方法实现如下

            private void InvokeAfterAttribute(object[] attributes, IMethodCallMessage callMsg, object result)
            {
                foreach (object obj2 in attributes)
                {
                    AfterAttribute attribute = obj2 as AfterAttribute;
                    if (attribute != null)
                    {
                        attribute.Invoke(this.m_Target, callMsg.MethodBase, callMsg.InArgs, result);
                    }
                }
                List<IInterception> interceptionList = ProxyBuilder.GetInterceptionList(this.m_Target.GetType().FullName + "." + callMsg.MethodName, InterceptionType.After);
                if (interceptionList != null)
                {
                    foreach (IInterception interception in interceptionList)
                    {
                        interception.Invoke(this.m_Target, callMsg.MethodBase, callMsg.InArgs, result);
                    }
                }
            }
    

    2.Interface Interceptor 代码

         public static object GetProxyInstance(object target, Type interfaceType)
            {
                return Activator.CreateInstance(GetProxyType(target.GetType(), interfaceType), new object[] { target, interfaceType });
            }
    
            private static Type GetProxyType(Type targetType, Type interfaceType)
            {
                AppDomain domain = Thread.GetDomain();
                AssemblyName name = new AssemblyName();
                name.Name = "TempAssemblyInjection";
                AssemblyName name2 = name;
                AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(name2, AssemblyBuilderAccess.Run);
                ModuleBuilder builder = assemblyBuilder.DefineDynamicModule("TempClassInjection");
                Type type = builder.GetType("TempAssemblyInjection__Proxy" + interfaceType.Name + targetType.Name);
                if (type != null)
                {
                    return type;
                }
                m_TypeBuilder = builder.DefineType("TempAssemblyInjection__Proxy" + interfaceType.Name + targetType.Name, TypeAttributes.Public, targetType.BaseType, new Type[] { interfaceType });
                m_Target = m_TypeBuilder.DefineField("target", interfaceType, FieldAttributes.Private);
                m_Interface = m_TypeBuilder.DefineField("iface", typeof(Type), FieldAttributes.Private);
                CreateConstructor(m_TypeBuilder, m_Target, m_Interface);
                foreach (MethodInfo info in interfaceType.GetMethods())
                {
                    CreateProxyMethod(info, m_TypeBuilder);
                }
                
                return m_TypeBuilder.CreateType();
                
            }
    

     上面代码通过Emit编程动态构建程序集,程序集中包括一个到目标类的代理类,针对给定接口中的方法签名逐个创建代理方法--语句CreateProxyMethod(info, m_TypeBuilder);
    另外可以看到代理类型的程序集只在第一次访问时被创建
    --语句 
     Type type = builder.GetType("TempAssemblyInjection__Proxy" + interfaceType.Name + targetType.Name);
       if (type != null)
        {
             return type;
         }

    建立的代理类定义类似如下代码:

    public class TempAssemblyInjection__ProxyIAnimalDog : IAnimal
    {
        // Fields
        private Type iface;
        private IAnimal target;
    
        // Methods
        public TempAssemblyInjection__ProxyIAnimalDog(object obj1, Type type1)
        {
            this.target = (IAnimal) obj1;
            this.iface = type1;
        }
    
        public override int Run(int num1, int num2)
        {
            object[] parameters = new object[] { num1, num2 };
            return (int) DynamicProxy.InterceptHandler(this.target, 
    Helper.GetMethodFromType(this.target.GetType(), MethodBase.GetCurrentMethod()),
    parameters,
    Helper.AspectUnion(Helper.GetMethodFromType(this.iface, MethodBase.GetCurrentMethod()).GetCustomAttributes(typeof(AspectAttribute), true))
    ); } }


     DynamicProxy.InterceptHandler的代码

            public static object InterceptHandlerMethod(object target, MethodBase method, object[] parameters, AspectAttribute[] attributes)
            {
                object obj2;
                foreach (AspectAttribute attribute in attributes)
                {
                    if (attribute is BeforeAttribute)
                    {
                        attribute.Invoke(target, method, parameters, null);
                    }
                }
                foreach (IInterception interception in ProxyBuilder.GetInterceptionList(target.GetType().FullName + "." + method.Name, InterceptionType.Before))
                {
                    interception.Invoke(target, method, parameters, null);
                }
                try
                {
                    obj2 = target.GetType().GetMethod(method.Name).Invoke(target, parameters);
                }
                catch (Exception exception)
                {
                    foreach (AspectAttribute attribute2 in attributes)
                    {
                        if (attribute2 is ExceptionAttribute)
                        {
                            attribute2.Invoke(target, method, parameters, exception);
                        }
                    }
                    foreach (IInterception interception2 in ProxyBuilder.GetInterceptionList(target.GetType().FullName + "." + method.Name, InterceptionType.Exception))
                    {
                        interception2.Invoke(target, method, parameters, exception);
                    }
                    throw;
                }
                foreach (AspectAttribute attribute3 in attributes)
                {
                    if (attribute3 is AfterAttribute)
                    {
                        attribute3.Invoke(target, method, parameters, obj2);
                    }
                }
                foreach (IInterception interception3 in ProxyBuilder.GetInterceptionList(target.GetType().FullName + "." + method.Name, InterceptionType.After))
                {
                    interception3.Invoke(target, method, parameters, obj2);
                }
                return obj2;
            }
    
            // Properties
            public static Callback InterceptHandler
            {
                get
                {
                    return new Callback(DynamicProxy.InterceptHandlerMethod);
                }
            }
    

    完成代码与使用Demo请下载演示包

    ==================================点这里下载=========================

  • 相关阅读:
    css常用标签
    关于手机端html的学习
    Vue_按键修饰符
    http_http协议简要概括
    nodejs_fs模块相关练习1
    nodejs_fs模块常用方法
    Vue_组件传值_非父子组件间的传值
    Vue_组件传值_子组件通过事件调用向父组件传值
    Vue_组件传值_父组件向子组件传值
    Vue_使用ref获取DOM元素
  • 原文地址:https://www.cnblogs.com/wdfrog/p/1988091.html
Copyright © 2011-2022 走看看