Flier Lu问到CLR Loader和Java Class Loader有什么不一样。要回答这个问题不容易,因为我对Java一窍不通。但既然问题提出来了,打肿脸来充胖子也得回答啊。
于是今天下午我在google上逛了一圈,找了些关于Java Class Loader的文章看了看。我的结论是,和Java Class Loader类似的东东,在CLR里是不存在的。
简单的说,CLR里不存在一个类似于Java.Lang.ClassLoader的东西。所以你无法实现你自己的CLR Loader。CLR里只有一个Loader,那就是CLR Loader。当然,CLR提供了自己独特的方式让你做动态装载。你所拥有的自由度是远比Java要大得多。
下面是具体分析。
我对Java Class Loader的理解主要是从这两篇文章里来的。
“Inside Class Loader” by Andeas Schaefer (http://www.onjava.com/lpt/a/4337) 和 “The basics of Java Class Loaders” by Chuck McManis (http://www.javaworld.com/javaworld/jw-10-1996/jw-10-indepth_p.html)。我看了看JVM Spec。但是我觉得不如上面两篇文章清楚。
先说Java里的Type吧。Java里的Type就是Class 。Class就是Namespace + class name. Class通过Class Loader来装载的。System Class Loader缺省的话只在CLASSPATH中寻找Class。如果你要在CLASSPATH之外转载Class的话,你就需要自己的Class Loader。如果两个Class有相同的名字,并且在同一个Class Loader里,那么它们就被JVM认为是相同的,可以互相赋值。如果有一个不一样的话,它们就被认为是不一样的。互相赋值会发生ClassCaseException。换句话说,Class name + Class Loader是一个Type的独特的ID。
Java的这个模型有很多问题。首先它把Class name做为Type的ID。两个Class如果有同样的名字,但是实际内容不一样的话,如果它们被同一个Class Loader装载,JVM会认为它们是同一个 Type。这个太搞笑了。结果就是Class Loader必须要有一些特别的办法来管理Class name。一般的办法是加一个前缀,比如说Class的URL。如果Namespace管理不好的话,很容易就是安全漏洞。这是为什么JVM Spec里提到Class Loader必须要让Parent Class Loader先搜索Class,再自己寻找。而且Class loader必须要保存Class resolution的结果,这样下次Class resolution的时候,Class loader会返回同样的结果。Java Class Loader有太多的限制,同时又有太多的责任。
另一个问题是共享问题。如果同一个Class被两个不同的Class Loader装载的话,JVM认为这两个Class不是同一个Type,不能互相赋值。结果就是Class无法共享。被不同Class Loader装载的Class无法直接对话。直接对话会产生linkage错误。它们只能间接对话,比如通过Interface,或者共同的Base Class。
还有一个问题是Versioning。因为Java的Type里只有名字,所以当你看到一个Type的时候,你无法知道它是第一版,还是第二版。所以如果你需要第二版,但是Class loader给你装载了第一版的时候,祈祷吧。也许上帝能救你。
现在回过头来看看CLR的模型。CLR的Type包括两部分:Class name + Assembly Name。Class name是和 Java的Type类似的东西,就是namespace。Assembly是Java没有的东西。Assembly Name的属性包括Name, Version, Culture, PublicKey(Token)。 如果两个Assembly有一个属性不一样,那么它们就认为是不一样的。两个Type如果有同样的Class name,但是Assembly Name不一样的话,它们也认为是不一样的。
CLR的Type引用总是包括Class name 和 Assembly Name的。所以CLR在寻找一个Type的时候,主要是寻找Assembly。找到了Assembly之后,CLR看看这个Assembly里有没有这个Class。有的话就万事大吉,没有的话就是TypeLoadException。
CLR区别Type主要靠Assembly。Assembly有PublicKey(Token)。别人无法冒充你。所以象Java里的namespace的问题就不存在了。Assembly有自己的Version。你要第二版的时候CLR不会装载第一版给你。所以象Java Class Loader那样的限制,责任和问题都不存在了。从这个角度上讲,这正是为什么CLR里没有象Java Class Loader那样的东西。
但并不是说你就不能动态装载了,而是说你动态装载的时候就不用考虑那些垃圾了。
关于共享的问题,因为没有了你自己的Class loader,所以任何Type都可以直接对话。同样的Type也不会因为Class Loader不一样而被认为不一样。
CLR Loader有自己的规则怎么寻找Assembly。它先看GAC,再看你的程序目录。都没有的话它还有一个AssemblyResolveEvent去问你,看你能不能提供。如果你要动态装载的话,你有Assembly.Load, Assembly.LoadFrom, Assembly.LoadFile, Assembly.Load(byte[])。你可以提供privateBin,你也可以提供codebase hint。你还能有policy。总之,你想从哪找,就可以去哪找。细节问题我就不多说了。你可以去看MSDN,Suzanne的Blog,Alan的Blog,和我的英文Blog.
结论,CLR Loader远比Java Class Loader要Secure, Powerful and Flexible。
posted on 2005-03-28 11:34
Brian Sun 阅读(686)
评论(1) 编辑 收藏 所属分类:
软件 、
转贴