为何采用双亲委派机制
一、雙親(父親)委派機(jī)制
java中存在3種類型的類加載器:引導(dǎo)類加載器,擴(kuò)展類加載器和系統(tǒng)類加載器。三者是的關(guān)系是:引導(dǎo)類加載器是擴(kuò)展類加載器的父類,擴(kuò)展類加載器是系統(tǒng)類加載器的父類。
- 引導(dǎo)類加載器(BootStrap)
主要負(fù)責(zé)加載jvm自身所需要的類,該加載器由C++實(shí)現(xiàn),加載的是<JAVA_HOME>/lib下的class文件,或-Xbootclasspath參數(shù)指定的路徑下的jar包加載到內(nèi)存中,注意必由于虛擬機(jī)是按照文件名識(shí)別加載jar包的,如rt.jar,如果文件名不被虛擬機(jī)識(shí)別,即使把jar包丟到lib目錄下也是沒(méi)有作用的(出于安全考慮,Bootstrap啟動(dòng)類加載器只加載包名為java、javax、sun等開(kāi)頭的類)。 - 拓展類加載器(Extension)
擴(kuò)展類加載器是指Sun公司(已被Oracle收購(gòu))實(shí)現(xiàn)的sun.misc.Launcher$ExtClassLoader類,由Java語(yǔ)言實(shí)現(xiàn)的,是Launcher的靜態(tài)內(nèi)部類,它負(fù)責(zé)加載<JAVA_HOME>/lib/ext目錄下或者由系統(tǒng)變量-Djava.ext.dir指定位路徑中的類庫(kù),開(kāi)發(fā)者可以直接使用標(biāo)準(zhǔn)擴(kuò)展類加載器。
- 系統(tǒng)類加載器
也稱應(yīng)用程序加載器是指 Sun公司實(shí)現(xiàn)的sun.misc.Launcher$AppClassLoader。它負(fù)責(zé)加載系統(tǒng)類路徑j(luò)ava -classpath或-D java.class.path指定路徑下的類庫(kù),也就是我們經(jīng)常用到的classpath路徑,開(kāi)發(fā)者可以直接使用系統(tǒng)類加載器,一般情況下該類加載是程序中默認(rèn)的類加載器,通過(guò)ClassLoade.getSystemClassLoader()方法可以獲取到該類加載器。
在Java的日常應(yīng)用程序開(kāi)發(fā)中,類的加載幾乎是由上述3種類加載器相互配合執(zhí)行的,在必要時(shí),我們還可以自定義類加載器,需要注意的是,Java虛擬機(jī)對(duì)class文件采用的是按需加載的方式,也就是說(shuō)當(dāng)需要使用該類時(shí)才會(huì)將它的class文件加載到內(nèi)存生成class對(duì)象,而且加載某個(gè)類的class文件時(shí),Java虛擬機(jī)采用的是雙親委派模式即把請(qǐng)求交由父類處理,它一種任務(wù)委派模式,下面我們進(jìn)一步了解它。
二、目的
- 都是用同名的類完成實(shí)例化的。
- 兩個(gè)實(shí)例各自對(duì)應(yīng)的同名的類的加載器必須是同一個(gè)。比如兩個(gè)相同名字的類,一個(gè)是用系統(tǒng)加載器加載的,一個(gè)擴(kuò)展類加載器加載的,兩個(gè)類生成的對(duì)象將被jvm認(rèn)定為不同類型的對(duì)象。
面試題:
能不能自己寫個(gè)類叫java.lang.System?
答案:通常不可以,但可以采取另類方法達(dá)到這個(gè)需求。
解釋:為了不讓我們寫System類,類加載采用委托機(jī)制,這樣可以保證爸爸們優(yōu)先,爸爸們能找到的類,兒子就沒(méi)有機(jī)會(huì)加載。而System類是Bootstrap加載器加載的,就算自己重寫,也總是使用Java系統(tǒng)提供的System,自己寫的System類根本沒(méi)有機(jī)會(huì)得到加載。
但是,我們可以自己定義一個(gè)類加載器來(lái)達(dá)到這個(gè)目的,為了避免雙親委托機(jī)制,這個(gè)類加載器也必須是特殊的。由于系統(tǒng)自帶的三個(gè)類加載器都加載特定目錄下的類,如果我們自己的類加載器加載一個(gè)特殊的目錄,那么系統(tǒng)的加載器就無(wú)法加載,也就是最終還是由我們自己的加載器加載。
------------------------------------------------------------------------------------------------------------------------------------------------------
什么是雙親委派機(jī)制
當(dāng)某個(gè)類加載器需要加載某個(gè).class文件時(shí),它首先把這個(gè)任務(wù)委托給他的上級(jí)類加載器,遞歸這個(gè)操作,如果上級(jí)的類加載器沒(méi)有加載,自己才會(huì)去加載這個(gè)類。
類加載器的類別
BootstrapClassLoader(啟動(dòng)類加載器)
c++編寫,加載java核心庫(kù) java.*,構(gòu)造ExtClassLoader和AppClassLoader。由于引導(dǎo)類加載器涉及到虛擬機(jī)本地實(shí)現(xiàn)細(xì)節(jié),開(kāi)發(fā)者無(wú)法直接獲取到啟動(dòng)類加載器的引用,所以不允許直接通過(guò)引用進(jìn)行操作
ExtClassLoader (標(biāo)準(zhǔn)擴(kuò)展類加載器)
java編寫,加載擴(kuò)展庫(kù),如classpath中的jre ,javax.*或者
java.ext.dir 指定位置中的類,開(kāi)發(fā)者可以直接使用標(biāo)準(zhǔn)擴(kuò)展類加載器。
AppClassLoader(系統(tǒng)類加載器)
java編寫,加載程序所在的目錄,如user.dir所在的位置的class
CustomClassLoader(用戶自定義類加載器)
java編寫,用戶自定義的類加載器,可加載指定路徑的class文件
源碼分析
?
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// 首先檢查這個(gè)classsh是否已經(jīng)加載過(guò)了Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {// c==null表示沒(méi)有加載,如果有父類的加載器則讓父類加載器加載if (parent != null) {c = parent.loadClass(name, false);} else {//如果父類的加載器為空 則說(shuō)明遞歸到bootStrapClassloader了//bootStrapClassloader比較特殊無(wú)法通過(guò)get獲取c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {}if (c == null) {//如果bootstrapClassLoader 仍然沒(méi)有加載過(guò),則遞歸回來(lái),嘗試自己去加載classlong t1 = System.nanoTime();c = findClass(name);sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}委派機(jī)制的流程圖
image.png
雙親委派機(jī)制的作用
1、防止重復(fù)加載同一個(gè).class。通過(guò)委托去向上面問(wèn)一問(wèn),加載過(guò)了,就不用再加載一遍。保證數(shù)據(jù)安全。
2、保證核心.class不能被篡改。通過(guò)委托方式,不會(huì)去篡改核心.clas,即使篡改也不會(huì)去加載,即使加載也不會(huì)是同一個(gè).class對(duì)象了。不同的加載器加載同一個(gè).class也不是同一個(gè)Class對(duì)象。這樣保證了Class執(zhí)行安全。
作者:秦時(shí)的明月夜
鏈接:https://www.jianshu.com/p/1e4011617650
來(lái)源:簡(jiǎn)書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
總結(jié)
以上是生活随笔為你收集整理的为何采用双亲委派机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 函数式接口@FunctionalInte
- 下一篇: 深入理解Java类加载机制