破坏双亲委派模型
轉(zhuǎn)載自?破壞雙親委派模型
?
1.第一次破壞
由于雙親委派模型是在JDK1.2之后才被引入的,而類加載器和抽象類java.lang.ClassLoader則在JDK1.0時代就已經(jīng)存在,面對已經(jīng)存在的用戶自定義類加載器的實現(xiàn)代碼,Java設計者引入雙親委派模型時不得不做出一些妥協(xié)。在此之前,用戶去繼承java.lang.ClassLoader的唯一目的就是為了重寫loadClass()方法,因為虛擬機在進行類加載的時候會調(diào)用加載器的私有方法loadClassInternal(),而這個方法唯一邏輯就是去調(diào)用自己的loadClass()。
2.第二次破壞
雙親委派模型的第二次“被破壞”是由這個模型自身的缺陷所導致的,雙親委派很好地解決了各個類加載器的基礎類的同一問題(越基礎的類由越上層的加載器進行加載),基礎類之所以稱為“基礎”,是因為它們總是作為被用戶代碼調(diào)用的API,但世事往往沒有絕對的完美。
如果基礎類又要調(diào)用回用戶的代碼,那該么辦?
一個典型的例子就是JNDI服務,JNDI現(xiàn)在已經(jīng)是Java的標準服務,
它的代碼由啟動類加載器去加載(在JDK1.3時放進去的rt.jar),但JNDI的目的就是對資源進行集中管理和查找,它需要調(diào)用由獨立廠商實現(xiàn)并部署在應用程序的ClassPath下的JNDI接口提供者的代碼,但啟動類加載器不可能“認識”這些代碼。
為了解決這個問題,Java設計團隊只好引入了一個不太優(yōu)雅的設計:線程上下文類加載器(Thread Context ClassLoader)。這個類加載器可以通過java.lang.Thread類的setContextClassLoader()方法進行設置,如果創(chuàng)建線程時還未設置,他將會從父線程中繼承一個,如果在應用程序的全局范圍內(nèi)都沒有設置過的話,那這個類加載器默認就是應用程序類加載器。
有了線程上下文加載器,JNDI服務就可以使用它去加載所需要的SPI代碼,也就是父類加載器請求子類加載器去完成類加載的動作,這種行為實際上就是打通了雙親委派模型層次結(jié)構(gòu)來逆向使用類加載器,實際上已經(jīng)違背了雙親委派模型的一般性原則,但這也是無可奈何的事情。Java中所有涉及SPI的加載動作基本上都采用這種方式,例如JNDI、JDBC、JCE、JAXB和JBI等。
3.第三次破壞
雙親委派模型的第三次“被破壞”是由于用戶對程序動態(tài)性的追求導致的,這里所說的“動態(tài)性”指的是當前一些非常“熱門”的名詞:代碼熱替換、模塊熱部署等,簡答的說就是機器不用重啟,只要部署上就能用。
OSGi實現(xiàn)模塊化熱部署的關鍵則是它自定義的類加載器機制的實現(xiàn)。每一個程序模塊(Bundle)都有一個自己的類加載器,當需要更換一個Bundle時,就把Bundle連同類加載器一起換掉以實現(xiàn)代碼的熱替換。在OSGi幻境下,類加載器不再是雙親委派模型中的樹狀結(jié)構(gòu),而是進一步發(fā)展為更加復雜的網(wǎng)狀結(jié)構(gòu),當受到類加載請求時,OSGi將按照下面的順序進行類搜索:
1)將java.*開頭的類委派給父類加載器加載。
2)否則,將委派列表名單內(nèi)的類委派給父類加載器加載。
3)否則,將Import列表中的類委派給Export這個類的Bundle的類加載器加載。
4)否則,查找當前Bundle的ClassPath,使用自己的類加載器加載。
5)否則,查找類是否在自己的Fragment Bundle中,如果在,則委派給Fragment Bundle的類加載器加載。
6)否則,查找Dynamic Import列表的Bundle,委派給對應Bundle的類加載器加載。
7)否則,類加載器失敗。
?
總結(jié)
- 上一篇: 剪辑视频电脑配置(视频 电脑配置)
- 下一篇: 剪辑视频电脑配置(视频 电脑 配置)