1. 程式人生 > >java類載入器——ClassLoader

java類載入器——ClassLoader

web rac rgb 好的 全盤負責機制 安全 trac 字節 如何

Java的設計初衷是主要面向嵌入式領域,對於自己定義的一些類,考慮使用依需求載入原則。即在程序使用到時才載入類,節省內存消耗,這時就可以通過類載入器來動態載入。

假設你平時僅僅是做web開發,那應該非常少會跟類載入器打交道,但假設你想深入學習tomcatserver的架構,它是不可缺少的。所謂類載入器。就是用於載入Java類到Java虛擬機中,它負責讀取Java字節碼。並轉換成java.lang.Class類的一個實例。使字節代碼.class文件得以執行。

一般類載入器負責依據一個指定的類找到相應的字節代碼,然後依據這些代碼定義成一個Java類。另外還負責載入資源。包含圖像文件和配置文件。

類載入器在實際使用中給我們帶來的優點是。它能夠使Java類動態地載入到JVM並執行。就可以在程序執行時再載入類,提供了非常靈活的動態載入方式。

比如我們熟悉的Applet,從遠程server下載字節碼到client動態載入到JVM便能夠執行。

在Java的龐大體系中,能夠將系統分為三種類載入器,各自是:

① 啟動類載入器(Bootstrap ClassLoader):載入對象是Java核心庫。把一些關鍵的Java類載入進JVM,這個載入器使用原生代碼(C/C++)實現的。並非繼承java.lang.ClassLoader,它是全部其它類載入器的終於父載入器,負責載入<JAVA_HOME>/jre/lib文件夾下且被JVM指定的類庫。事實上它屬於JVM總體的一部分,JVM一啟動就將這些指定的類載入到內存中,避免以後過多的I/O操作。提高系統的執行效率。

啟動類載入器無法被Java程序直接使用。

② 擴展類載入器(Extension ClassLoader):載入的對象為Java的擴展庫。即載入<JAVA_HOME>/jre/lib/ext文件夾裏面的類。

這個類由上面的Bootstrap ClassLoader載入,但因為Bootstrap ClassLoader並不是用Java實現,已經脫離了Java體系,所以假設嘗試調用擴展類載入器的getParent()方法獲取父載入器會得到null,但它的父類載入器是Bootstrap ClassLoader。

Java中能夠直接使用擴展類載入器。

③ 應用程序類載入器(Application ClassLoader):亦叫系統類載入器(System ClassLoader),它負責載入用戶類路徑(CLASSPATH)指定的類庫。假設程序沒有自定義類載入器。就默認使用應用程序類載入器。它也由Bootstrap ClassLoader載入。但它的父載入類被設置成了Extension ClassLoader。

假設要使用這個載入器,可通過ClassLoader.getSystemClassLoader()獲取。

假如有一天你心血來潮也想自己寫一個類載入器,那麽你僅僅須要繼承java.lang.ClassLoader類就可以。於是能夠用以下的圖2-4-1來清晰表示出各種類載入器的關系,Bootstrap ClassLoader是最根本的類載入器,其不存在父類載入器,Extension ClassLoader由Bootstrap ClassLoader載入。所以它的父類載入器是Bootstrap ClassLoader。Application ClassLoader也是由Bootstrap ClassLoader載入,但它的父載入器被指向了Extension ClassLoader,而其它全部用戶自己定義的類載入器都由Application ClassLoader載入。

由此能夠看出越重要的類載入器就越早被JVM載入,這是考慮到安全性。由於先載入的類載入器會充當下一個類載入器的父載入器,在雙親委派模型機制下,就能確保安全性。

那麽什麽是雙親委派模型?比方爺爺、爸爸、你三代單傳,你們家族都遺傳懶惰基因,每當遇到事情都互相推脫,如今須要一個人去買一包鹽,不然今晚的菜就有色無味了。而你第一個被托付去超市買,但因為你的懶惰。你向你爸爸撒了一頓嬌,你爸爸受不了你僅僅能答應幫你去,在懶惰的驅使下,你爸爸最後找了一個借口說要趕工作。讓你爺爺出去走動走動順便買一包鹽,就這樣你爺爺僅僅能乖乖去超市買鹽。

雙親委派模型就類似這種機制。類載入器載入類時首先托付給父類載入器載入。除非父類載入器不能載入才自己載入。

這樣的模型要求除了頂層的啟動類載入器外,其它的類載入器都要有自己的父類載入器。假如有一個類要載入進來。一個類載入器並不會立即嘗試自己將其載入,而是委派到父類載入器。父類載入器收到後又嘗試委派到其父類載入器,以此類推,直到委派到啟動類載入器,這樣一層一層往上委派。僅僅有當父類載入器反饋自己沒法完畢這個載入時,子載入器才會嘗試自己載入。通過這個機制。保證了Java應用所使用的都是同一個版本號的Java核心庫的類。同一時候這個機制也保證了安全性,設想假設Application ClassLoader想要載入一個有破壞性的java.lang.System類,雙親委派模型會一層層向上委派,終於委派給Bootstrap ClassLoader,而Bootstrap ClassLoader檢查到緩存中已經有了這個類。並不會再載入這個有破壞性的System類。

另外,類載入器還擁有全盤負責機制,即當一個ClassLoader載入一個類時,這個類所依賴的、引用的其它全部類都由這個ClassLoader載入,除非在程序中顯性地指定另外一個ClassLoader載入。

技術分享

圖2-4-1 類載入器關系

在Java中。我們用全然匹配類名來標識一個類。即用包名和類名。而在JVM中。一個類由全然匹配類名和一個類載入器的實例ID作為唯一標識。

即是說同一個虛擬機能夠有兩個包名、類名都相同的類。僅僅要他們由兩個不同類載入器載入。

於是當我們在Java中常常說兩個類相不相等,必須是針對同一個類載入器載入的前提下才有意義。否則就算是相同的字節代碼,由不同類載入器載入,這兩個類也不是相等的。這樣的特征為我們提供了隔離機制,在tomcatserver中是十分實用的。

了解了JVM的類載入器的各種機制後,看看一個類是如何被類載入器載入進來的。一個類準備載入,類載入器先推斷此類是否已經被載入過(載入過的類會被緩存在內存中),假設緩存中存在此類則直接返回這個類。

否則獲取父類載入器,假設父類載入器為null,則由Bootstrap ClassLoader載入並返回Class。假設父類載入器不為null,則由父類載入器載入。載入成功就返回Class,載入失敗則依據類路徑查找class文件,找到就載入此class並返回Class,找不到就拋出ClassNotFoundException異常。

技術分享

圖2-4-2 類載入過程

類載入器屬於JVM級別的設計,我們非常多時候基本不會跟他打交道,可是假如你想了解整個JAVA體系是怎樣工作的,假如你要設計開發自己的框架或中間件或一個較龐大的java軟件。那麽你必須熟悉類載入器的相關機制,在現實的設計中,依據實際情況利用類載入器能夠提供類庫的隔離及共享,保證你的軟件不同級別的邏輯切割程序不會互相影響,提供更好的安全性。



喜歡研究java的同學能夠交個朋友,以下是本人的微信號:

技術分享

java類載入器——ClassLoader