JAVA類(lèi)加載器包括幾種枪蘑?
引導(dǎo)類(lèi)加載器 bootstrap class loader
啟動(dòng)類(lèi)加載器主要加載的是JVM自身需要的類(lèi)垒玲,這個(gè)類(lèi)加載使用C++語(yǔ)言實(shí)現(xiàn)的陆馁,是虛擬機(jī)自身的一部分,它負(fù)責(zé)將 /lib路徑下的核心類(lèi)庫(kù)或-Xbootclasspath參數(shù)指定的路徑下的jar包加載到內(nèi)存中合愈,注意必由于虛擬機(jī)是按照文件名識(shí)別加載jar包的叮贩,如rt.jar,如果文件名不被虛擬機(jī)識(shí)別佛析,即使把jar包丟到lib目錄下也是沒(méi)有作用的(出于安全考慮益老,Bootstrap啟動(dòng)類(lèi)加載器只加載包名為java、javax寸莫、sun等開(kāi)頭的類(lèi)
擴(kuò)展類(lèi)加載器 extensions class loader
它負(fù)責(zé)加載JAVA_HOME/lib/ext目錄下或者由系統(tǒng)變量-Djava.ext.dir指定位路徑中的類(lèi)庫(kù)捺萌,開(kāi)發(fā)者可以直接使用標(biāo)準(zhǔn)擴(kuò)展類(lèi)加載器。
應(yīng)用程序類(lèi)加載器 application class loader
應(yīng)用程序加載器是指 Sun公司實(shí)現(xiàn)的sun.misc.Launcher$AppClassLoader储狭。它負(fù)責(zé)加載系統(tǒng)類(lèi)路徑j(luò)ava -classpath或-D java.class.path 指定路徑下的類(lèi)庫(kù)互婿,也就是我們經(jīng)常用到的classpath路徑,開(kāi)發(fā)者可以直接使用系統(tǒng)類(lèi)加載器辽狈,一般情況下該類(lèi)加載是程序中默認(rèn)的類(lèi)加載器慈参,通過(guò)ClassLoader#getSystemClassLoader()方法可以獲取到該類(lèi)加載器。
自定義類(lèi)加載器 java.lang.classloder
就是自定義啦刮萌,通過(guò)繼承java.lang.ClassLoader類(lèi)的方式
類(lèi)加載器之間的關(guān)系
啟動(dòng)類(lèi)加載器驮配,由C++實(shí)現(xiàn),沒(méi)有父類(lèi)。
拓展類(lèi)加載器(ExtClassLoader)壮锻,由Java語(yǔ)言實(shí)現(xiàn)琐旁,父類(lèi)加載器為null
系統(tǒng)類(lèi)加載器(AppClassLoader),由Java語(yǔ)言實(shí)現(xiàn)猜绣,父類(lèi)加載器為ExtClassLoader
自定義類(lèi)加載器灰殴,父類(lèi)加載器肯定為AppClassLoader。
雙親委派機(jī)制
請(qǐng)注意雙親委派模式中的父子關(guān)系并非通常所說(shuō)的類(lèi)繼承關(guān)系掰邢。
其工作原理的是:如果一個(gè)類(lèi)加載器收到了類(lèi)加載請(qǐng)求牺陶,它并不會(huì)自己先去加載,而是把這個(gè)請(qǐng)求委托給父類(lèi)的加載器去執(zhí)行辣之,如果父類(lèi)加載器還存在其父類(lèi)加載器掰伸,則進(jìn)一步向上委托,依次遞歸怀估,請(qǐng)求最終將到達(dá)頂層的啟動(dòng)類(lèi)加載器狮鸭,如果父類(lèi)加載器可以完成類(lèi)加載任務(wù),就成功返回多搀,倘若父類(lèi)加載器無(wú)法完成此加載任務(wù)歧蕉,子加載器才會(huì)嘗試自己去加載,這就是雙親委派模式酗昼,即每個(gè)兒子都很懶廊谓,每次有活就丟給父親去干,直到父親說(shuō)這件事我也干不了時(shí)麻削,兒子自己想辦法去完成蒸痹。
雙親委派機(jī)制作用
通過(guò)這種層級(jí)關(guān)可以避免類(lèi)的重復(fù)加載,當(dāng)父親已經(jīng)加載了該類(lèi)時(shí)呛哟,就沒(méi)有必要子ClassLoader再加載一次叠荠。其次是考慮到安全因素,java核心api中定義類(lèi)型不會(huì)被隨意替換扫责,假設(shè)通過(guò)網(wǎng)絡(luò)傳遞一個(gè)名為java.lang.Integer的類(lèi)榛鼎,通過(guò)雙親委托模式傳遞到啟動(dòng)類(lèi)加載器,而啟動(dòng)類(lèi)加載器在核心Java API發(fā)現(xiàn)這個(gè)名字的類(lèi)鳖孤,發(fā)現(xiàn)該類(lèi)已被加載者娱,并不會(huì)重新加載網(wǎng)絡(luò)傳遞的過(guò)來(lái)的java.lang.Integer,而直接返回已加載過(guò)的Integer.class苏揣,這樣便可以防止核心API庫(kù)被隨意篡改
作用:保證JDK核心類(lèi)的優(yōu)先加載黄鳍;
如何自定義一個(gè)類(lèi)加載器?
通過(guò)繼承ClassLoad定義一個(gè)類(lèi)加載器平匈。
應(yīng)用場(chǎng)景
如Tomcat容器框沟,每個(gè)WebApp有自己的ClassLoader,加載每個(gè)WebApp的ClassPath路徑上的類(lèi)藏古,一旦遇到Tomcat自帶的Jar包就委托給CommonClassLoader加載。同包的隔離忍燥。另外成熟的開(kāi)源框架拧晕,都有自己的classloade。
特殊情況破壞雙親委派加載機(jī)制:?
當(dāng)java有些類(lèi)當(dāng)中梅垄,有時(shí)候核心的類(lèi)加載到時(shí)候需要用到用戶子提供的類(lèi)厂捞,典型的jidn服務(wù)中,因?yàn)檫@種情況會(huì)破壞雙親委派機(jī)制哎甲,java推出了線程上下文類(lèi)加載器蔫敲。也就是父類(lèi)加載器請(qǐng)求子類(lèi)加載器去完成類(lèi)加載的動(dòng)作饲嗽,這種行為實(shí)際上就是打通了雙親委派模型的層次結(jié)構(gòu)來(lái)逆向使用類(lèi)加載器炭玫,實(shí)際上已經(jīng)違背了雙親委派模型的一般性原則,但這也是無(wú)可奈何的事情貌虾。Java中所有涉及SPI的加載動(dòng)作基本上都采用這種方式吞加,例如JNDI、JDBC尽狠、JCE衔憨、JAXB和JBI等
問(wèn)題:java當(dāng)中都有哪幾種類(lèi)加載器,相互有什么聯(lián)系
答:java中有引導(dǎo)類(lèi)加載器主要加載jvm中需要的類(lèi)袄膏、擴(kuò)展類(lèi)加載器主要加載lib下的類(lèi)践图、應(yīng)用程序加載器主要加載是classpath的類(lèi)、自定義類(lèi)加載器沉馆。
問(wèn)題:1.8為什么用metaspace替換掉permgen,matespace保存在哪里
答:permgen叫做Permanent Generation space码党,是內(nèi)存的永久保存區(qū),這個(gè)永久保存區(qū)的大小不好設(shè)定斥黑,不要調(diào)優(yōu)揖盘,可以簡(jiǎn)化full gc,可以在GC不進(jìn)行暫停的情況下并發(fā)地釋放類(lèi)數(shù)據(jù),元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機(jī)中,而是使用本地內(nèi)存锌奴。