天天看點

雙親委派機制_雙親委派機制可以被打破嗎?模型可以被破壞嗎?前言一、雙親委派機制是什麼?二、雙親委派機制該怎麼打破?三、雙親委派機制模型怎麼被破壞的?

前言

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

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

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

雙親委派機制_雙親委派機制可以被打破嗎?模型可以被破壞嗎?前言一、雙親委派機制是什麼?二、雙親委派機制該怎麼打破?三、雙親委派機制模型怎麼被破壞的?

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常見問答相關知識的話,請多多關注小編的更新吧

繼續閱讀