Launcher啟動類
本文是雙親委派機制的源碼分析部分,類加載機制中的雙親委派模型對於jvm的穩定運行是非常重要的
不過源碼其實比較簡單,接下來簡單介紹一下
我們先從啟動類說起
有一個Launcher類 sun.misc.Launcher;
仔細看下這簡短的幾行注釋,可以得到有用的信息
ps:直接IDE里面查看反編譯的,看不到注釋的,可以下載openJDK查看源碼,我的這個版本是openjdk-8-src-b132-03_mar_2014
sun.misc.Launcher 這個類是系統用於啟動主應用的啟動器 |
構造方法 Launcher() 中做了四件事情
創建 擴展 類加載器 |
創建 應用程序 類加載器 |
設置ContextClassLoader |
如果需要安裝安全管理器 security manager |
其中launcher是staitc的,所以初始化的時候就會創建對象,也就是觸發了構造方法,所以初始化的時候就會執行上面四個步驟
ExtClassLoader 和 AppClassLoader 都是Launcher的靜態內部類
而且,他們也都是ClassLoader的實現類
看下ExtClassLoader的創建中的關鍵幾步
也在看下AppClassLoader的創建中的關鍵幾步
另外還有
Launcher類中的靜態變量
你應該可以想得到下面這三個到底是什么東西,如果真不懂,你需要再去研究下
System.getProperty("sun.boot.class.path")
System.getProperty("java.ext.dirs")
System.getProperty("java.class.path")
ClassLoader的構造方法
前面說過,對於虛擬機來說只有兩種類加載器
啟動類加載器以及其他所有,而其他所有都是java.lang.ClassLoader的子類
所以想要自定義類加載器,必須要繼承實現ClassLoader
而且,我們上面說到的,java給我們提供的AppClassLoader 和 ExtClassLoader 也都是ClassLoader的子類
看下ClassLoader的構造方法 和變量parent
你會發現,其實構造方法實際上只有雙參數版本這一種
第二個參數為parent,這個parent是一個ClassLoader, 用於記錄他的 父 類加載器
不管調用哪個構造方法
parent必然會被初始化
要么是你調用帶參數的構造方法, 顯式指定一個來設置parent
如果你不指定,默認的構造方法,會使用 getSystemClassLoader返回的AppClassLoader 設置parent
|
ps:
本文中的不少地方,我都在"父類加載器" 的"父 "和"類加載器"中間加了幾個空格
千萬不要理解成父類加載器 ,<父 類加載器> 指的是類加載器的加載順序層級結構的優先順序 而不是平時說的繼承關系中的父類 父 意味着他的上一層級
getSystemClassLoader 獲取AppClassLoader 的過程
|
那么再回頭看一眼 應用程序 類加載器的構造
擴展 類加載器作為參數傳遞給了他,他最終調用的就是ClassLoader 的一個參數的構造方法
將ExtClassLoader 設置為 AppClassLoader 的parent
而ExtClassLoader,他的parent 是null
ps:啟動 類加載器 是虛擬機的一部分,可能c/c++/java實現的,所以不是java語言的一部分
所以對於java本身來說,可以說他是不存在的,但是JVM是知道他的
所以說,此處為null ,parent為null說明他的父 類加載器是啟動類加載器 或者可能就是啟動 類加載器本身
loadClass與findClass
想要實現類 加載器,需要繼承ClassLoader
並且有兩個重要的方法
看下兩個重要方法的聲明,你可能就感覺出來了,想想public 和 protected都是啥意思?
loadClass方法是類加載器執行 加載類邏輯 的方法,包括檢查是否已經加載,調用父類加載,失敗則自己嘗試使用 findClass方法加載 |
findClass當前類加載器 實際執行加載二進制流的具體行為方法 |
Launcher.APPClassLoader中的loadClass方法,最終調用的是super.loadClass , 實際上就是ClassLoader的loadClass方法
Launcher.ExtClassLoader 根本就沒有實現自己的loadClass 方法,所以使用的也是ClassLoader中的
|
再來看看ClassLoader的loadClass方法
他會調用parent的loadClass方法,如果他的parent不為空,將會一直調用父 類加載器, 直到最頂級的 啟動 類加載器
如果 啟動 類加載器仍舊找尋不到, 那么調用自身的findClass
如果自己調用findClass加載失敗呢?
很顯然, 函數調用結束之后,會返回到調用點位置,調用棧的形式嘛
也就是經過
必然要繼續執行他的下一段
如果沒拋出異常的話,就會走到下面這里
顯然這就完成了一整個的雙親委派的類加載模式
總結
Launcher作為啟動器
創建了ExtClassLoader 以及AppClassLoader
他們都是ClassLoader的子類,並且ClassLoader有一個parent 指向他的父 類加載器
正是這個屬性完成了自頂而下的 優先級層級順序的確定
對於sun內置的ExtClassLoader 以及AppClassLoader 以及啟動 類加載器 Bootstrap 他們的層級為
Bootstrap>ExtClassLoader>ExtClassLoader
並且,他們各自有不同的分工
通過ClassLoader的loadClass方法,確定了他們的調用邏輯,也就是雙親委派機制
每個層級都會向上傳遞類加載請求,只有上層 父 類加載器調用失敗,才會自己嘗試加載
雙親委派機制的意義重大,帶來了更高的安全性等優點
不過他的實現邏輯卻是的確很簡單
一個loadClass就搞定了
findClass是類加載器自身加載類的具體行為
所以,如果你不需要破壞雙親委派機制,只需要覆蓋這個方法即可
如果你想要完全自定義你的類加載器的邏輯機制,直接覆蓋loadClass,當然,你可能還需要繼續覆蓋findClass