雙親委派機制可以被打破嗎?模型可以被破壞嗎?

前言

大家都知道雙親委派機制是什麼吧,那你們知道雙親委派機制該怎麼打破嗎?它的模型又是怎麼被破壞的呢?下面小編就帶你詳細瞭解瞭解吧。

一、雙親委派機制是什麼?

一般的說,一個個特定的類加載器它在接到需要加載類的請求時,它會首先查看自己已加載完的類中是否包含這個類,如果有就返回,沒有的話就會把加載的任務交給父類加載器加載,以此遞歸,父類加載器如果可以完成類加載任務,就返回它,當父類加載器無法完成這個加載任務時,纔會不得已自己去加載。

雙親委派機制可以被打破嗎?模型可以被破壞嗎?

 

ClassLoaderA和ClassLoaderB是我們已經實現的類加載器,這裏把它們都指定了父加載器爲APPClassLoader,由於往上最多隻能拿到SystemClassLoader的引用,所以父加載器最多隻能指定到SystemClassLoader。

二、雙親委派機制該怎麼打破?

兩種方法:

1. 自定義類加載器,重寫loadClass方法;

2. 使用線程上下文類加載器;

三、雙親委派機制模型怎麼被破壞的?

雙親委派機制有三次破壞歷史:

一次破壞

因爲雙親委派模型是JDK1.2之後才被引入,而類加載器和抽象類java.lang.ClassLoader則在JDK1.0時就已經存在,所以在面對已存在的用戶自定義類加載器的實現代碼時,Java設計者引入雙親委派模型時不得不做出一些妥協。在此之前,用戶去繼承java.lang.ClassLoader的唯一目的就是爲了重寫loadClass()方法,這是源於虛擬機進行類加載的時候會調用加載器的私有方法loadClassInternal(),而這個方法的唯一邏輯就是去調用自己的loadClass()。

二次破壞

第二次「破壞」是因爲模型自身缺陷所致,雙親委派很好地解決了各個類加載器的基礎類的統一問題,那問題就來了,如果基礎類又要調用回用戶的代碼,該怎麼辦?

例:JNDI服務

它的代碼是啓動類加載器去加載的,JNDI的目的是爲了對資源進行集中管理與查找,它需要調用由獨立廠商實現並部署在應用程序的ClassPath下的JNDI接口提供者的代碼,但啓動類加載器顯然不會知道這些代碼。

由此,Java的設計團隊引入了一個不怎麼優雅的設計:線程上下文類加載器;這個類加載器可以通過java.lang.Thread類的setContextClassLoader()方法進行設置,在創建線程時如果還未設置的話,他會從父線程中繼承一個,如果在應用程序的全局範圍內都沒有設置過的話,那麼這個類加載器默認就是應用程序類加載器。

這樣,JNDI服務就可以去加載它所需要的SPI代碼,但這種打通了雙親委派模型層次結構由此來逆向使用類加載器的行爲,實際上就已經違背了雙親委派模型的一般性原則!

三次破壞

雙親委派模型的第三次「被破壞」源於用戶對程序動態性的追求。

OSGi實現模塊化熱部署的核心在於它自定義的類加載器機制的實現。所有的程序模塊(Bundle)都有一個自己的類加載器,當需要更換一個Bundle時,就把Bundle連同類加載器一起換掉來實現代碼的熱替換。在OSGi幻境下,類加載器不再是雙親委派模型中的樹狀結構,而是進一步發展爲更加複雜的網狀結構,當受到類加載請求時,OSGi將按照下面的順序進行類搜索:

1)把java.*開頭的類委派給父類加載器加載。

2)不然,把委派列表名單內的類委派給父類加載器加載。

3)不然,把Import列表中的類委派給Export這個類的Bundle的類加載器加載。

4不然,就查找當前Bundle的ClassPath,並使用自己的類加載器加載。

5)不然,就查找類是否在自己的Fragment Bundle中,如果在,則委派給Fragment Bundle的類加載器加載。

6)不然,就查找Dynamic Import列表的Bundle,委派給對應Bundle的類加載器加載。

7)不然,類加載器失敗。

好了,這就是本文的全部內容了,如果你還想要了解更多java常見問答相關知識的話,請多多關注小編的更新吧