眾所周知,Java 2之後在ClassLoader中使用了parent-Delegation模式,目的是為了簡化User-defined ClassLoader的實現和更好的安全性。
ClassLoader通常作為Java 安全性的第一道屏障,
- 它會阻止惡意代碼對原有可信任代碼的幹擾。
- 保護可信任代碼。
- 將不同的代碼分類(稱之為protection domains 或 runtime domain)。
ClassLoader會在運行時將每一個載入過的class分配到一個唯一命名空間([i]name-space[/i])之下。不同的class根據載入的class loader的不同,被分配到不同的name-space。JVM會為每一個class loader維護一個唯一的name-space名稱。一旦一個class A 已經被載入並且被安置在name-space N下,就不可能在載入另一個A 在同一個name-space下。如果強制這麼做(通過user-defined class loader),會得到一個LinkageError(duplicate class definition:[your class name])。有時這個name-space也稱為[i]runtime package[/i] ,Java語言中的包訪問成員(friendly)實際上指的是運行時包訪問可見,而不是編譯時間。因此當你試圖訪問不在同一個runtime package的成員是(即便在編譯時間它們在同一個包內,但是卻由不同的class loader載入)也同樣會得到java.lang.IllegalAccessException: Class A can not access a member of class B with modifiers "" 這樣的異常。
一個User-defined必須依賴其他的Class loader,至少需要system class loader,來協助它完成對某些class的載入工作。在1.2之後,每一個class loader除了bootstrap class loader都有一個parent class loader。每一次需要載入class時,首先會去請求parent class loader來載入這個class,如果不成功才會自己進行載入工作。這稱為parent-delegation model。
如果你違反了這一協定的話,通常你會得到一個NoClassDefFoundError。因為你的class Loader無法找到一些Java API中的類 ,比如說java.lang.Object。
你可能想如果將這些Java API中的類也放在你的class loader的路徑下,是否就可以了呢?JVM不會允許你這樣做的。你會得到:java.lang.SecurityException: Prohibited package name: java.lang,這樣的異常。在Java 1.2之後,所有的java core api都由一個JVM內建的class loader載入,並且java 安全機制不允許這些類或介面被除此之外的class loader載入。
在一個預設的JVM環境下,通常存在兩個Class Loader。一個就是所謂的bootstrap class loader,它用來載入所有的java core api(包括所有java包下的類),另一個是系統class loader,它用來載入你定義的class_path下的類。
通常使用Class.getClassLoader()方法可以查詢到載入這個class的class loader的資訊。但是對於sun 的 jvm 實現而言,對於core api的class這樣做只會得到null。(見 java doc)。
Ps: 系統class loader為sun.misc.Launcher$AppClassLoader。
原文地址:http://www.chinaitpower.com/A200507/2005-07-24/165821.html