天天看點

Java 類加載器( ClassLoader)淺析 類加載器操作三原則[譯]

類加載器操作三原則[譯]

SEP 8TH, 2013 | COMMENTS

(出自一本 J2EE 的教材中關于類加載器的介紹,原文已不知所蹤。)

類加載的 bug,一旦在程式設計中遇到很難調試。好消息是,了解類加載的過程中,我們隻需要牢記住三條基本原則。如果你能清晰的了解這三條基本原則,所有問題都迎刃而解。下面,我們開始介紹。

委托原則(Delegation Principle)

如果一個類還沒有被加載,類加載器會委托它的父親加載器去加載它。

這種委托會一直延續,直到到達委托層次的最頂層,由原始的類加載器加載完成該類。下圖展示了這種情況。

Java 類加載器( ClassLoader)淺析 類加載器操作三原則[譯]

Systm-ClassPath classloader 加載了 MyApp.MyApp,而這個類創造了一個 java.util.Vector。假設現在 java.util.Vector 還沒又被加載。因為 System-Classpath classloader 加載了 MyApp 類,它首先請求它的父親 extension classloader 來加載這個類(java.util.Vector)。而 extension classloader 又請求 Bootstrap classloader 嘗試加載。因為 java.util.Vector 是 J2SE 類,bootstrap classloader 成功加載了它。

考慮一個當略微不同的情況,如下圖。

Java 類加載器( ClassLoader)淺析 類加載器操作三原則[譯]

在這種情況中,MyApp 創造了一個新的使用者自定義類的執行個體,MyClass。假設 MyClass 還沒有被加載。像以往一樣,當 System-Classpath classloader 接收到這個加載請求,它委托了它的父親。最終這個委托傳遞到了 Bootstrap classloader。但是在 java 核心 API 裡,找不到這個類。是以它的孩子加載器 Extensions classloader 嘗試加載它。同樣的,Extensions classloader 也沒有找到它。最終,委托請求回到了 System-Classpath classloader 這裡。它找到了這個類并加載成功。

可見性原則(Visibility principle)

被父親類加載器加載的類對于孩子加載器是可見的,但關系相反相反則不可見。

這說明,一個類隻能看見它自己的加載器或者這個加載器的父類加載器加載的類,反過來是不可以的。比如,被 ClassX 的父親加載器加載的類是不能看見 ClassX 的。為了更清楚的了解,讓我們來看一個例子,如下圖。

Java 類加載器( ClassLoader)淺析 類加載器操作三原則[譯]

圖中展示了四個類加載器。類加載器 A 是最頂層的加載器,B 是它的孩子。類加載器 X 和 Y 是 B 的孩子。他們各自都加載了與自己同名的類。類加載器 A 能看見 A 類,類加載器 B 能看見 A,B 類。類似的,X 能看見 A,B,X,Y 能看見 A,B,Y。但兄弟、Y 之間的類是不可見的。

獨特性原則(Uniqueness Principle)

當一個類加載器加載一個類時,它的孩子加載器絕不會重新加載這個類。

這是因為委托原則中,一個加載器總是會委托自己的父親加載器加載類。當層次中的父親加載器無法加載類的時候,孩子類加載器就會(或者嘗試去)加載這個類。這樣,類加載的獨特性就得到了保障。當父親和孩子加載器加載了同一個類,一個有趣的情況就出現了。你可能會想這怎麼可能出現?這不是違反了獨特性原則?

我們用可見性原則中的示例圖來解釋這個問題。我們假設沒有任何類被加載到這些類加載器的層次結構中。假設 X 類被類加載器 X 加載,它強制性的用類加載器 X 加載 B 類。這可以通過像 Class.Name()這樣的 API 來實作,代碼如下:

1
2
3
4
5
6
7
      
public class X {

   public X() {
      ClassLoader cl = this.getClass().getClassLoader();
      Class B = Class.forName(“B”, true, cl);
   }
}

           

在 X 的構造函數中,B 被顯示的使用類加載器 X 加載。如果另一個被類加載器 B 加載的類需要通路 B 類,則無法實作,因為委托原則隻能向父親方向查詢。如果類加載器 B 也加載了 B 類,當比較兩個 B 類的執行個體時,如果一個執行個體來自于類加載器 X,一個來自于類加載器 B,則會抛出 ClassCastException 異常。

總結

這三個原則 是解決程式中遇到的類加載問題的關鍵所在。在實際的程式設計中,并不需要顯示的調用到類加載器,它主要出現在一些架構的代碼中。但對于每一個開發者、架構師而言,都必須了解類加載的層次結構,這樣才能寫出優雅的代碼。

PS

注意,雖然 java 的加載實作中,對于 bootstrap classloader 、extensions classloader 和 system classloader 來說,他們的關系是 parent-first,也就是像原則一中所說的那樣,需要向上委托,但使用者自定義的 classloader 完全可以跳出這個圈子,自己實作 parent-lastclassloader。比如 Websphere 中就有相關配置。

更具體的類加載器程式設計執行個體,請見另外一篇博文:《Java 類加載器程式設計實踐》

 原文位址:http://biaobiaoqi.github.com/blog/2013/09/08/three-principles-of-classloader-operation/

 版權聲明:自由轉載-非商用-非衍生-保持署名| Creative Commons BY-NC-ND 3.0