.Net中的Interception–一個簡單的AOP架構學習

來源:互聯網
上載者:User

最近翻手頭的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請下載示範包

==================================點這裡下載=========================

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.