[五]類加載機制雙親委派機制 底層代碼實現原理 源碼分析 java類加載雙親委派機制是如何實現的


 

Launcher啟動類


本文是雙親委派機制的源碼分析部分,類加載機制中的雙親委派模型對於jvm的穩定運行是非常重要的
不過源碼其實比較簡單,接下來簡單介紹一下
 
我們先從啟動類說起
有一個Launcher類   sun.misc.Launcher;
image_5b8be55e_4272
 
仔細看下這簡短的幾行注釋,可以得到有用的信息
ps:直接IDE里面查看反編譯的,看不到注釋的,可以下載openJDK查看源碼,我的這個版本是openjdk-8-src-b132-03_mar_2014
 
sun.misc.Launcher
這個類是系統用於啟動主應用的啟動器
 
構造方法 Launcher() 中做了四件事情
創建          擴展          類加載器
創建          應用程序    類加載器
設置ContextClassLoader
如果需要安裝安全管理器 security manager
其中launcher是staitc的,所以初始化的時候就會創建對象,也就是觸發了構造方法,所以初始化的時候就會執行上面四個步驟
image_5b8be55e_3add
 
ExtClassLoader 和  AppClassLoader  都是Launcher的靜態內部類
image_5b8be55e_6921
而且,他們也都是ClassLoader的實現類
image_5b8be55e_3cb7
 
看下ExtClassLoader的創建中的關鍵幾步
image_5b8be55e_77fe
 
也在看下AppClassLoader的創建中的關鍵幾步
image_5b8be55e_7080
 
另外還有
Launcher類中的靜態變量
image_5b8be55e_62a5
 
你應該可以想得到下面這三個到底是什么東西,如果真不懂,你需要再去研究下
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
 
 
 
image_5b8be55e_2925
ps:
本文中的不少地方,我都在"父類加載器" 的"父 "和"類加載器"中間加了幾個空格
千萬不要理解成父類加載器  ,<父    類加載器> 指的是類加載器的加載順序層級結構的優先順序   而不是平時說的繼承關系中的父類 父 意味着他的上一層級
 
getSystemClassLoader 獲取AppClassLoader 的過程
image_5b8be55f_2f0b
 
那么再回頭看一眼  應用程序   類加載器的構造
擴展  類加載器作為參數傳遞給了他,他最終調用的就是ClassLoader 的一個參數的構造方法  
將ExtClassLoader 設置為 AppClassLoader  的parent
image_5b8be55f_4098
 
而ExtClassLoader,他的parent 是null
image_5b8be55f_53e0
 
ps:啟動  類加載器 是虛擬機的一部分,可能c/c++/java實現的,所以不是java語言的一部分
所以對於java本身來說,可以說他是不存在的,但是JVM是知道他的
所以說,此處為null ,parent為null說明他的父    類加載器是啟動類加載器   或者可能就是啟動  類加載器本身

loadClass與findClass

想要實現類 加載器,需要繼承ClassLoader
並且有兩個重要的方法
看下兩個重要方法的聲明,你可能就感覺出來了,想想public 和 protected都是啥意思?
image_5b8be55f_6d2f
 
loadClass方法是類加載器執行   加載類邏輯   的方法,包括檢查是否已經加載,調用父類加載,失敗則自己嘗試使用 findClass方法加載
findClass當前類加載器 實際執行加載二進制流的具體行為方法
 
Launcher.APPClassLoader中的loadClass方法,最終調用的是super.loadClass  , 實際上就是ClassLoader的loadClass方法
Launcher.ExtClassLoader  根本就沒有實現自己的loadClass 方法,所以使用的也是ClassLoader中的
 
image_5b8be55f_66ff
 
再來看看ClassLoader的loadClass方法
他會調用parent的loadClass方法,如果他的parent不為空,將會一直調用父 類加載器, 直到最頂級的  啟動   類加載器 
如果 啟動   類加載器仍舊找尋不到, 那么調用自身的findClass 
image_5b8be55f_2ac5
 
如果自己調用findClass加載失敗呢?
很顯然, 函數調用結束之后,會返回到調用點位置,調用棧的形式嘛
也就是經過
image_5b8be55f_1e1a
必然要繼續執行他的下一段
如果沒拋出異常的話,就會走到下面這里
image_5b8be55f_5b1f
顯然這就完成了一整個的雙親委派的類加載模式
 
image_5b8be55f_4c07
 

總結

Launcher作為啟動器
創建了ExtClassLoader 以及AppClassLoader
他們都是ClassLoader的子類,並且ClassLoader有一個parent  指向他的父   類加載器
正是這個屬性完成了自頂而下的 優先級層級順序的確定
對於sun內置的ExtClassLoader 以及AppClassLoader  以及啟動  類加載器 Bootstrap  他們的層級為
Bootstrap>ExtClassLoader>ExtClassLoader
並且,他們各自有不同的分工
通過ClassLoader的loadClass方法,確定了他們的調用邏輯,也就是雙親委派機制
每個層級都會向上傳遞類加載請求,只有上層  父     類加載器調用失敗,才會自己嘗試加載
雙親委派機制的意義重大,帶來了更高的安全性等優點
不過他的實現邏輯卻是的確很簡單
一個loadClass就搞定了
findClass是類加載器自身加載類的具體行為
所以,如果你不需要破壞雙親委派機制,只需要覆蓋這個方法即可
如果你想要完全自定義你的類加載器的邏輯機制,直接覆蓋loadClass,當然,你可能還需要繼續覆蓋findClass
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM