• NET Framework:Application Domain


    Application Domain可以看作是一个Assembly的逻辑容器。在程序执行过程中,如果遇到需要的Type并没有定义在已经加载的Assemblies中,CLR会把相应的Assembly加载的该Application Domain中。每个Application Domain都有一个属于自己的加载器堆(Loader Heap),用于维护从Application Domain创建以后所用到的所有的Type,以及这些Type对应的方法表——维护这样一个Mapping:定义在Type中的所有方法和经过JIT编译后x86代码(只考虑32bit处理器)。      Application Domain之间是相互隔离,互不干扰。在一个Application Domain创建的对象不能被另一个Application Domain直接调用,反映在内存分配上面——就是各个Application Domain使用各个独立的内存地址空间。一个对象根据他所对应的类型(如System.MarshalByRefObject通过传递引用的方式)或者属性(比如对于定义了System. SerializableAttribute的Type采用传递值得方式)以两种不同的方式在Application Domain之间传递——By Reference 和By Value。      这些都是地球人都知道的.NET的基本原理,但是相信很多人没有尝试过通过Coding的方式证明这种机制。      那么现在我们就先来看看我们的Sample:         using System;   using System.Collections.Generic;   using System.Text;   using System.Runtime.Remoting;   using System.Reflection;   using Artech.AppDomainIsolation;      namespace Artech.AppDomainIsolation   {    public class GeneralType    {    AppDomain GetAppDomain()    {    return AppDomain.CurrentDomain;    }    }       [Serializable]    public class MarshalByValueType    {    public AppDomain GetAppDomain()    {    return AppDomain.CurrentDomain;    }    }       public class MarshalByRefType : MarshalByRefObject    {    public AppDomain GetAppDomain()    {    return AppDomain.CurrentDomain;    }    }    class Program    {       static void Main(string[] args)    {    AppDomain appDomain = AppDomain.CreateDomain("newAppDomain");       string assemblyName = "Artech.AppDomainIsolation";    try    {    GeneralType generalObject = (GeneralType)appDomain.CreateInstanceAndUnwrap(assemblyName, "Artech.AppDomainIsolation.GeneralType");    }    catch (Exception ex)    {    Console.WriteLine("Fail to pass a general type instance created in another application domain to default appliction domain,beacuse /"{0}/"", ex.Message);    }       MarshalByValueType marshalByValueObject = (MarshalByValueType)appDomain.CreateInstanceAndUnwrap(assemblyName, "Artech.AppDomainIsolation.MarshalByValueType");    MarshalByRefType marshalByRefObject = (MarshalByRefType)appDomain.CreateInstanceAndUnwrap(assemblyName, "Artech.AppDomainIsolation.MarshalByRefType");       Console.WriteLine("/nmarshalByValueObject is a transparent proxy? {0}.",RemotingServices.IsTransparentProxy(marshalByValueObject)?"Yes":"No");    Console.WriteLine("marshalByRefObject is a transparent proxy? {0}.", RemotingServices.IsTransparentProxy(marshalByRefObject) ? "Yes" : "No");       AppDomain appDomain_MarshalByValueType = marshalByValueObject.GetAppDomain();    AppDomain appDomain_MarshalByRefType = marshalByRefObject.GetAppDomain();       Console.WriteLine("/nThe method of marshalByValueObject is executed in the default application domain?/"{0}/"",    object.ReferenceEquals(AppDomain.CurrentDomain, appDomain_MarshalByValueType) ? "Yes" : "No");    Console.WriteLine("The method of marshalByRefObject is executed in the default application domain?/"{0}/"",    object.ReferenceEquals(AppDomain.CurrentDomain, appDomain_MarshalByRefType) ? "Yes" : "No");       AppDomain.Unload(appDomain_MarshalByRefType);    marshalByValueObject.GetAppDomain();       try    {    marshalByRefObject.GetAppDomain();    }    catch (Exception ex)    {    Console.WriteLine("/nAn exception is thorwn when calling the method of marshalByRefObject because /"{0}/"", ex.Message);    }    Console.Read();    }    }   }         下面是运行结果的Screen Shot。               接下来我们来分析这段代码。      1. 我们首先定义个3个不同的Type,他们都一个相同的方法——GetAppDomain()用于获取执行该方法的真正的Application Domain。      GeneralType:一般的Type, 没有什么特别。   MarshalByValueType:定义了一个System. SerializableAttribute(你也可以通过使它实现System.Runtime.Serialization.ISerializable Interface来模拟这个Sample),它将以By Value的方式在不同的Application Domain之间传递。   MarshalByRefType:继承自System. MarshalByRefObject。该类型的对象它将以By Reference的方式在不同的Application Domain之间传递。      public class GeneralType    {    AppDomain GetAppDomain()    {    return AppDomain.CurrentDomain;    }    }       [Serializable]    public class MarshalByValueType    {    public AppDomain GetAppDomain()    {    return AppDomain.CurrentDomain;    }    }       public class MarshalByRefType : MarshalByRefObject    {    public AppDomain GetAppDomain()    {    return AppDomain.CurrentDomain;    }    }      2. 在Main()中我们首先创建一个新的Application Domain,并为他指定一个Friendly Name——newAppDomain。      AppDomain appDomain = AppDomain.CreateDomain("newAppDomain");   3. 接着我们分别在这个新建的Appliation Domain中创建我们在1中定义的3个类型的对象——generalObject,marshalByValueObject,marshalByRefObject,并试着把它传递到当前的Application Domain——Default Application Domain。从运行的结果我们可以看出,当我们传递generalObject的时候,一个Exception被抛出,从Error Message可以开出原因——“Type 'Artech.AppDomainIsolation.GeneralType' in assembly 'Artech.AppDomainIsolation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.”从而我们可以看出,一般的Type是不能在不同的Application之间传递的。      try    {    GeneralType generalObject = (GeneralType)appDomain.CreateInstanceAndUnwrap(assemblyName, "Artech.AppDomainIsolation.GeneralType");    }    catch (Exception ex)    {    Console.WriteLine("Fail to pass a general type instance created in another application domain to default appliction domain,beacuse /"{0}/"", ex.Message);    }       MarshalByValueType marshalByValueObject = (MarshalByValueType)appDomain.CreateInstanceAndUnwrap(assemblyName, "Artech.AppDomainIsolation.MarshalByValueType");    MarshalByRefType marshalByRefObject = (MarshalByRefType)appDomain.CreateInstanceAndUnwrap(assemblyName, "Artech.AppDomainIsolation.MarshalByRefType");      4. 通过3,证明了标记的System. SerializableAttribute属性和继承自System. MarshalByRefObject的Type对应的对象是可以在不同的Application Domain之间传递呢。但是他们之间又会有怎样的差异呢?他们是真正的对象呢?还仅仅是位于新建Application Domain中的对象一个代理(Proxy)?我们通过调用定义在System.Runtime.Remoting中的静态方法: IsTransparentProxy。了解Remoting的人相信对这个方法不会感到陌生。他用于判断某个对象是否是一个Transparent Proxy(在当我们跨Application Domain远程调用一个Remote Object的时候,实际上我们并非直接调用Remote Object的方法,而是通过一个同Client处在同一个Application Domain的Transparent Proxy对象间接地调用远程对象——Transparent Proxy具有一个Remote Object的Reference,可以轻易地找到这个Remote Object。其实在真正的场景中,Client调用Transparent Proxy,Transparent Proxy再去调用Real Proxy,Real Proxy最终才去调用Remote Object——如果你想进一步地了解Remoting,你可以参照MSDN)         Console.WriteLine("/nmarshalByValueObject is a transparent proxy? {0}.",RemotingServices.IsTransparentProxy(marshalByValueObject)?"Yes":"No");    Console.WriteLine("marshalByRefObject is a transparent proxy? {0}.", RemotingServices.IsTransparentProxy(marshalByRefObject) ? "Yes" : "No");      通过运行结果,我们可以看到:MarshalByValueType对象marshalByValueObject,IsTransparentProxy方法返回False。而对于MarshalByRefType对象marshalByRefObject则返回True。这就充分证明了,标记了System. SerializableAttribute属性的Type所对应的对象是一个真正意义上的对象,而对于继承自MarshalByRefObject Type,当该Type对应的对象从一个Application Domain传递到另一个Application Domain后,另一个Application Domain获得的仅仅是原来对象的Proxy而已。      我们可以从传递的机制来解释这种差异。当你把System. SerializableAttribute属性运用要某个Type,或者让某个Class实现System.Runtime.Serialization.ISerializable Interface的时候,你实际上是给该Type赋予了一种能力——一种可以序列化成XML的能力(XMLSerializer负责把对象序列化成XML)。当这种对象从一个Application Domain传递到另一个Application Domain的时候,Object先被序列化成XML,接着把XML传递到另一个Application Domain中,在新的Application Domain中,通过反序列化重新生成一个新的Object——这个新的Object和处于另一个Application Domain已经没有任何关系。      而对于而对于继承自MarshalByRefObject Type的对象,虽然他不能够序列化成XML,但是可以通过传递Reference的方式在Application Domain之间 传递。当这种传递实质上是通过在另一个Application创建一个拥有该对象引用的一个Proxy。而这个Proxy依赖一这个处理另一个Application Domain的真正对象。      5. 上面我们实际上已经说清楚了两个对象传递的差异——By Value 和By Reference。现在我们来进一步验证前面我们说的。我们继续来看看我们的代码:         AppDomain appDomain_MarshalByValueType = marshalByValueObject.GetAppDomain();   AppDomain appDomain_MarshalByRefType = marshalByRefObject.GetAppDomain();       Console.WriteLine("/nThe method of marshalByValueObject is executed in the default application domain?/"{0}/"",    object.ReferenceEquals(AppDomain.CurrentDomain, appDomain_MarshalByValueType) ? "Yes" : "No");    Console.WriteLine("The method of marshalByRefObject is executed in the default application domain?/"{0}/"",    object.ReferenceEquals(AppDomain.CurrentDomain, appDomain_MarshalByRefType) ? "Yes" : "No");      我们通过调用连个对象的GetAppDomain()方法,从而获得真正执行该方法的Application Domain。然后再和当前的Application Domain进行比较。我们发现对于MarshalByValueType对象marshalByValueObject,真正执行操作是在当前的Application Domain中进行的。而对于MarshalByRefType对象marshalByRefObject,则是我们新建立的Application Domain。这充分证明了当marshalByValueObject传递到新的Application后,生成一个和原来对象一模一样的对象,这个对象具有执行自身操作的能力。而对于marshalByRefObject,由于它只是一个Proxy而已,他只有把对对象的操作请求发送给真正的,位于另一个Application Domain的真正对象(同时他也负责把远程对象的执行结果返回给调用者),真正的操作实际上是发生在远程对象的Application Domain。      由于marshalByRefObject,依赖于远程对象,所以当我们卸载掉Host远程对象的Application Domain,对marshalByRefObject的任何调用将变得无效。所以这里可以对下面这段代码作出解释。      AppDomain.Unload(appDomain_MarshalByRefType);   marshalByValueObject.GetAppDomain();       try    {    marshalByRefObject.GetAppDomain();    }    catch (Exception ex)    {    Console.WriteLine("/nAn exception is thorwn when calling the method of marshalByRefObject because /"{0}/"", ex.Message);    }      注:在分布式开发中,我们会大量接触到By Value 和By Refernce传递。一般而言,By Value用于商业实体的传递(Business Entity),而By Reference用于远程调用(RPC)或者是调用Service。
  • 相关阅读:
    UVA 11488 Hyper Prefix Sets (字典树)
    UVALive 3295 Counting Triangles
    POJ 2752 Seek the Name, Seek the Fame (KMP)
    UVA 11584 Partitioning by Palindromes (字符串区间dp)
    UVA 11100 The Trip, 2007 (贪心)
    JXNU暑期选拔赛
    计蒜客---N的-2进制表示
    计蒜客---线段的总长
    计蒜客---最大质因数
    JustOj 2009: P1016 (dp)
  • 原文地址:https://www.cnblogs.com/hainange/p/6153275.html
Copyright © 2020-2023  润新知