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 閱讀(698)
評論(1) 編輯 收藏 所屬分類:
軟件 、
轉貼