文章目錄
- 1. 雙親委派機制
- 2. 證明
- 3. 優勢與劣勢
1. 雙親委派機制
類加載器用來把類加載到 Java 虛擬機中。從JDK1.2版本開始,類的加載過程采用雙親委派機制,這種機制能更好地保證 Java 平臺的安全。
1.定義
如果一個類加載器在接到加載類的請求時,它首先不會自己嘗試去加載這個類,而是把這個請求任務委托給父類加載器去完成,依次遞歸,如果父類加載器可以完成類加載任務,就成功返回。只有父類加載器無法完成此加載任務時,才自己去加載。
2.本質
規定了類加載的順序是:引導類加載器先加載,若加載不到,由擴展類加載器加載,若還加載不到,才會由系統類加載器或自定義的類加載器進行加載。
2. 證明
雙親委派機制在 java.lang.ClassLoader.loadClass(String,boolean)
接口中體現。該接口的邏輯如下:
(1)先在當前加載器的緩存中查找有無目標類,如果有,直接返回。
(2)判斷當前加載器的父加載器是否為空,如果不為空,則調用parent.loadClass(name, false)
接口進行加載。
(3)反之,如果當前加載器的父類加載器為空,則調用findBootstrapClassOrNull(name)
接口,讓引導類加載器進行加載。
(4)如果通過以上3條路徑都沒能成功加載,則調用findClass(name)
接口進行加載。該接口最終會調用java.lang.ClassLoader
接口的defineClass
系列的native
接口加載目標 Java 類。
雙親委派的模型就隱藏在這第2和第3步中。
2.舉例
假設當前加載的是java.lang.Object
這個類,很顯然,該類屬于JDK中核心得不能再核心的一個類,因此一定只能由引導類加載器進行加載。當JVM準備加載javaJang.Object
時,JVM默認會使用系統類加載器去加載,按照上面4步加載的邏輯,在第1步從系統類的緩存中肯定查找不到該類,于是進入第2步。由于從系統類加載器的父加載器是擴展類加載器,于是擴展類加載器繼續從第1步開始重復。由于擴展類加載器的緩存中也一定査找不到該類,因此進入第2步。擴展類的父加載器是null,因此系統調用findClass(String)
, 最終通過引導類加載器進行加載。
3. 優勢與劣勢
1.雙親委派機制優勢
避免類的重復加載,確保一個類的全局唯一性
Java類隨著它的類加載器一起具備了一種帶有優先級的層次關系,通過這種層級關系可以避免類的重復加載,當父親已經加載了該類時,就沒有必要子ClassLoader再加載一次。
保護程序安全,防止核心API被隨意篡改
2.雙親委托模式的弊端
檢查類是否加載的委托過程是單向的,這個方式雖然從結構上說比較清晰,使各個ClassLoader的職責非常明確,但是同時會帶來一個問題,即頂層的ClassLoader無法訪問底層的ClassLoader所加載的類。
通常情況下,啟動類加載器中的類為系統核心類,包括一些重要的系統接口,而在應用類加載器中,為應用類。按照這種模式,應用類訪問系統類自然是沒有問題,但是系統類訪問應用類就會出現問題。比如在系統類中提供了一個接口,該接口需要在應用類中得以實現,該接口還綁定一個工廠方法,用于創建該接口的實例,而接口和工廠方法都在啟動類加載器中。這時,就會出現該工廠方法無法創建由應用類加載器加載的應用實例的問題。
3.結論:
由于Java虛擬機規范并沒有明確要求類加載器的加載機制一定要使用雙親委派模型,只是建議采用這種方式而已。
比如在Tomcat中,類加載器所采用的加載機制就和傳統的雙親委派模型有一定區別,當缺省的類加載器接收到一個類的加載任務時,首先會由它自行加載,當它加載失敗時,才會將類的加載任務委派給它的超類加載器去執行,這同時也是Servlet規范推薦的一種做法。