寄宿 和 应用程序域(一)
概念:
寄宿(hosting),准确的说是CLR所支持的寄宿,是程序A(宿主,可以是托管或非托管代码)中调用第三方代码(寄宿代码)B。
这个调用过程与我们直接引用第三方代码不同之处在于,通过CLR应用程序域对第三方代码进行了隔离。
也就是说第三方代码B运行于CLR创建的应用程序域内。
其优点就是对第三方代码很好的隔离作用。防止第三方代码破坏程序本身的代码或数据。
应用程序域(Appdomain),简言之是CLR创建的一个逻辑隔离区,这个隔离区内运行的代码不能访问其他应用程序域中的代码。
CLR初始化后会创建一个默认 应用程序域,在我们不人为创建新的appdomain的前提下,我们所写的代码就会在这个默认appdomain中运行。这个默认appdomain 直到进程终止才会被销毁。
注:因为寄宿代码是依赖于CLR运行,所以寄宿代码(第三方代码)必须是CLR可以支持的代码,直白些说,必须为exe或者dll
对于寄宿,大概有以下情况:
1、如果宿主是非托管代码,宿主程序进程会根据寄宿代码的版本加载对应版本的CLR,CLR会在默认的应用程序域内执行寄宿代码。
非托管代码的寄宿调用大致如下:
宿主通过调用 C:\Windows\System32\MSCorEE.dll中CLRCreateInstance函数返回ICLRMetaHost接口
调用ICLRMetaHost接口的GetRuntime函数返回一个指向非托管接口ICLRRuntimeInfo的指针
通过这个指针调用GetInterface方法会的ICLRRuntimeHost接口。
通过ICLRRuntimeHost接口可以做如下控制:
设置宿主管理器,宿主可以参与CLR的内存分配,线程调度,垃圾回收以及特定操作的超时通知等。
获取CLR管理器。告诉CLR阻止使用的类型及成员。以及特定事件发生时素质应调用的方法。
初始化启动CLR。
加载程序集,并执行其中代码。
停止CLR。
2、如果宿主为托管代码,且宿主运行CLR版本与寄宿代码CLR版本不同。
假设宿主运行于.net framework 4.0,寄宿代码运行于.net framework 2.0,这时 宿主会在进程中加载.net framework 2.0,并以此版本CLR运行寄宿代码。
当CLR加载到进程后,就永远不能被卸载,直到该进程结束为止。意味着,上面同时加载两种版本CLR后,即使寄宿代码 应用程序卸载,内存被回收,CLR 2.0依然存在,直到进程终止。
一个进程中同时支持两种CLR版本是在.net framework 4.0引进的。之前的版本只能支持一种CLR。
3、如果寄宿代码为托管代码,且宿主与寄宿代码CLR版本相同。
则宿主以当前CLR创建应用程序域 运行寄宿代码。
Appdomain提供功能如下:
1、 隔离,appdomain间代码不能直接访问。
为了提供良好的隔离性,每个appdomain会单独加载程序集,即使两个appdomain用了同一个程序集,这个程序集也会被分别加载进两个appdomain中,这当然会造成资源的浪费,但其优点是,不会发生当某个appdomain被卸载时,会对其他appdomain产生影响。
对于常用的程序集,则会有多个appdomain共享,如MSCorLib.dll。对于此种程序集,CLR会维护一个特殊的Loader堆,给Loader堆中所有的类型、对象、代码会被进程中所有的appdomain共享。其缺点是,这个方式加载的程序集永远不能被卸载,直到进程结束。
2、Appdomain可以被卸载
CLR提供了卸载appdomain的能力。卸载一个appdomain,其中包含的所有程序集都会被卸载。
3、appdomain可以单独权限设置
创建appdomain可以对其配置权限信息。这可以限制寄宿代码无权限对宿主进行破坏。
4、appdomain可以单独配置
可对appdomain中程序集的加载方式、搜索路径、版本绑定及加载器优化等进行相关配置。
寄宿 AppDomain用途:
例子:假如我们需要开发一个web服务器程序主要用于运行asp.net。
我们已经开发了大部分功能,但是对于动态页面服务器代码的解析并不擅长。
不过这正是CLR的所擅长的,所以对于静态资源的请求我们可以直接返回。对于动态页面的请求。我们可以通过CLR的寄宿功能的执行动态页面代码,而后返回html。
实际上,aps.net正是这么做的。
当客户端首次请求一个web应用程序时。
asp.net会加载CLR,并告诉CLR为此web应用程序创建一个AppDomain,该AppDomain会加载与请求相关的程序集,创建类型实例,调用执行,返回客户端的请求。
当该web应用的第二第三个请求到来时,会在此已有的AppDomain中执行。
当有新的web应用请求时,则会创建新的AppDomain处理请求。
此时,每一个web应用程序对应一个AppDomain,每一个web应用程序异常或是停止,都不会影响其他web应用程序的正常运行。
使用场景:
以下场景或许我们可以用到 寄宿 AppDomain
1、非托管代码可以利用寄宿而运行已有的第三方代码。
2、不同安全级别的程序集,可以放在不同权限的AppDomain中运行。
3、当某些代码不稳定 或 资源消耗较大 等情况时,可以放在一个单独的AppDomain中运行。出现问题,则卸载该AppDomain
4、由于进程的创建较慢 并有较大的资源消耗,或可以在AppDomain运行代码 代替以进程运行。
5、由于.net framework 兼容性的提升,可以在程序中运行两个不同版本的程序集
对于真正掌握这个技术后,或许可以使用的场景成千上万,只是局限于自己的想象力。