溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java的三次破壞雙親委派模型是什么

發(fā)布時間:2021-10-11 10:54:19 來源:億速云 閱讀:109 作者:iii 欄目:編程語言

這篇文章主要介紹“Java的三次破壞雙親委派模型是什么”,在日常操作中,相信很多人在Java的三次破壞雙親委派模型是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java的三次破壞雙親委派模型是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

Java的三次破壞雙親委派模型是什么

類加載

我們平常寫的代碼是保存在一個 .java文件里面,經(jīng)過編譯會生成.class文件,這個文件存儲的就是字節(jié)碼,如果要用上我們的代碼,那就必須把它加載到  JVM 中。

Java的三次破壞雙親委派模型是什么

當然,加載到 JVM 生成 class 對象的來源不一定得是.class文件,也可以來自網(wǎng)絡等等,反正只要是符合 JVM 規(guī)范的都行。

而類加載的步驟主要分為:加載、鏈接、初始化。

加載

其實就是找到字節(jié)流,然后將其加載到 JVM 中,生成類對象。這個階段就是類加載器派上用場的階段,等下我們再細說。

鏈接

這個階段是要讓生成的類對象融入到 JVM 中,分別要經(jīng)歷以下三個步驟:

Java的三次破壞雙親委派模型是什么

驗證就是檢驗一下加載的類是否滿足 JVM 的約束條件,也就是判斷是否合規(guī)。

準備就是為加載類的靜態(tài)變量申請內(nèi)存空間,并賦予初始值,例如是 int 類型那初始值就是 0。

解析就是將符號引用解析成為實際引用,講人話就是:例如 Yes 類里面引用了一個 XX 類,那一開始 Yes 類肯定不知道 XX  類在內(nèi)存里面的地址,所以就先搞個符號引用替代一下,假裝知道,等類加載解析的時候再找到 XX 類真正地址,做一個實際引用。

這就是解析要做的事情。還有一點,雖說把解析放到鏈接階段里面,但是 JVM 規(guī)范并沒有要求在鏈接過程中完成解析。

初始化

這個階段就是為常量字段賦值,然后執(zhí)行靜態(tài)代碼塊,將一堆要執(zhí)行的靜態(tài)代碼塊方法包裝成 clinit 方法執(zhí)行,這個方法會加鎖,由 JVM 來保證  clinit 方法只會被執(zhí)行一次。

所以可以用一個內(nèi)部靜態(tài)類來實現(xiàn)延遲初始化的單例設計模式,同時保證了線程安全。

這個階段完畢之后,類加載過程就 ok 了,可以投入使用啦,再來畫個圖匯總一下:

Java的三次破壞雙親委派模型是什么

雙親委派模型

加載階段,需要用到類加載器來將 class 文件里面的內(nèi)容搞到 JVM 中生成類對象。

那什么是雙親委派模型?

雙親委派模型用一句話講就是子類加載器先讓父類加載器去查找該類來加載,父類又繼續(xù)請求它的父類直到最頂層,在父類加載器沒有找到所請求的類的情況下,子類加載器才會嘗試去加載,這樣一層一層上去又下來。

Java的三次破壞雙親委派模型是什么

每個類加載器都有固定的查找類的路徑,在 JDK8 的時候一共有三種類加載器。

  • 啟動類加載器(Bootstrap ClassLoader),它是屬于虛擬機自身的一部分,用 C++  實現(xiàn)的,主要負責加載

    \lib目錄中或被 -Xbootclasspath  指定的路徑中的并且文件名是被虛擬機識別的文件。它是所有類加載器的爸爸。
  • 擴展類加載器(Extension ClassLoader),它是 Java  實現(xiàn)的,獨立于虛擬機,主要負責加載

    \lib\ext目錄中或被 java.ext.dirs 系統(tǒng)變量所指定的路徑的類庫。
  • 應用程序類加載器(Application  ClassLoader),它是Java實現(xiàn)的,獨立于虛擬機。主要負責加載用戶類路徑(classPath)上的類庫,如果我們沒有實現(xiàn)自定義的類加載器那這玩意就是我們程序中的默認加載器。

Java的三次破壞雙親委派模型是什么

為什么要提出雙親委派模型?

其實就是為了讓基礎類得以正確地統(tǒng)一地加載。

從上面的圖可以看出,如果你也定義了一個  java.lang.Object類,通過雙親委派模式是會把這個請求委托給啟動類加載器,它掃描\lib目錄就找到了 jdk 定義的  java.lang.Object 類來加載,所以壓根不會加載你寫的 java.lang.Object類,這就可以避免一些程序不小心或者有意的覆蓋基礎類。

至此我們已經(jīng)清楚了什么是雙親委派,和為什么要雙親委派。接下來我們來看看三次破壞。

第一次破壞

在 jdk 1.2 之前,那時候還沒有雙親委派模型,不過已經(jīng)有了 ClassLoader 這個抽象類,所以已經(jīng)有人繼承這個抽象類,重寫 loadClass  方法來實現(xiàn)用戶自定義類加載器。

而在 1.2 的時候要引入雙親委派模型,為了向前兼容, loadClass 這個方法還得保留著使之得以重寫,新搞了個 findClass  方法讓用戶去重寫,并呼吁大家不要重寫 loadClass 只要重寫 findClass。

這就是第一次對雙親委派模型的破壞,因為雙親委派的邏輯在 loadClass 上,但是又允許重寫  loadClass,重寫了之后就可以破壞委派邏輯了。

第二次破壞

第二次破壞指的是 JNDI、JDBC 之類的情況。

首先得知道什么是 SPI(Service Provider Interface),它是面向拓展的,也就是說我定義了個規(guī)矩,就是 SPI  ,具體如何實現(xiàn)由擴展者實現(xiàn)。

像我們比較熟的 JDBC 就是如此。

MySQL 有 MySQL 的 JDBC 實現(xiàn),Oracle 有 Oracle 的 JDBC 實現(xiàn),我 Java  不管你內(nèi)部如何實現(xiàn)的,反正你們這些數(shù)據(jù)庫廠商都得統(tǒng)一按我這個來,這樣我們 Java 開發(fā)者才能容易的調(diào)用數(shù)據(jù)庫操作,所以在 Java 核心包里面定義了這個  SPI。

而核心包里面的類都是由啟動類加載器去加載的,但它的手只能摸到\lib或Xbootclasspath指定的路徑中,其他的它鞭長莫及。

而 JDBC 的實現(xiàn)類在我們用戶定義的 classpath  中,只能由應用類加載器去加載,所以啟動類加載器只能委托子類來加載數(shù)據(jù)庫廠商們提供的具體實現(xiàn),這就違反了自下而上的委托機制。

具體解決辦法是搞了個線程上下文類加載器,通過setContextClassLoader()默認情況就是應用程序類加載器,然后利用Thread.current.currentThread().getContextClassLoader()獲得類加載器來加載。

這就是第二次破壞雙親委派模型。

第三次破壞

這次破壞是為了滿足熱部署的需求,不停機更新這對企業(yè)來說至關重要,畢竟停機是大事。

OSGI  就是利用自定義的類加載器機制來完成模塊化熱部署,而它實現(xiàn)的類加載機制就沒有完全遵循自下而上的委托,有很多平級之間的類加載器查找,具體就不展開了,有興趣可以自行研究一下。

這就是第三次破壞。

第四次破壞

在 JDK9 引入模塊系統(tǒng)之后,類加載器的實現(xiàn)其實做了一波更新。

像擴展類加載器被重命名為平臺類加載器,核心類加載歸屬了做了一些劃分,平臺類加載器承擔了更多的類加載,上面提到的  -Xbootclasspath、java.ext.dirs 也都無效了,rt.jar 之類的也被移除,被整理存儲在 jimage 文件中,通過新的 JRT  文件系統(tǒng)訪問。

當收到類加載請求,會先判斷該類在具名模塊中是否有定義,如果有定義就自己加載了,沒的話再委派給父類。

關于 JDK9 相關的知識點就不展開了,有興趣的自行查閱。

所以這就是第四次破壞。

其他注意點

首先,雖說是子類父類,但是加載器之間的關系不是繼承,而是組合。

Java的三次破壞雙親委派模型是什么

看下代碼就很清晰了,具體的邏輯如下:

Java的三次破壞雙親委派模型是什么

在 JVM 中,類的唯一性是由類加載器實例和類的全限定名一同確定的,也就是說即使是同一個類文件加載的類,用不同的類加載器實例加載,在 JVM  看來這也是兩個類。

到此,關于“Java的三次破壞雙親委派模型是什么”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI