類加載器三杰
jvm有三類classloader,分別是bootstrapclassloader,extendedclassloader以及systemclassloader箩做。
bootstrap classloader是系統(tǒng)在啟動(dòng)jvm時(shí)默認(rèn)加載的。當(dāng)用戶在命令行輸入java Test時(shí)靴寂,系統(tǒng)會(huì)首先加載jvm塘揣。在windows系統(tǒng)下辛掠,jvm的路徑通常位于%JAVA_HOME%/jdk/jre/client/jvm.dll和%JAVA_HOME%/jdk/jre/server/jvm.dll.
bootstrap classloader加載后弥激,會(huì)載入extended classloader进陡,并將extended classloader的父類設(shè)為bootstrap classloader。然后微服,bootstrap classloader接著載入system classloader趾疚,并將system classloader的父類設(shè)為extended classloader。至此以蕴,bootstrap--extended--system三級(jí)繼承結(jié)構(gòu)形成糙麦。
bootstrap classloader在jvm啟動(dòng)之后自動(dòng)加載。bootstrap ?classloader由c實(shí)現(xiàn)丛肮,不屬于java類喳资。
extended classloader由java實(shí)現(xiàn),通常為sun.misc.Lancher$ExtClassLoader.
system classloader由java實(shí)現(xiàn)腾供,通常為sun.misc.Lancher$AppClassLoader.
其中,
bootstrap classloader負(fù)責(zé)加載sun.boot.class.path路徑下的.class文件以及jar包。
extended classloader負(fù)責(zé)加載java.ext.dirs路徑下的.class文件以及jar包伴鳖。
system classloader負(fù)責(zé)加載java.class.path路徑下的.class文件以及jar包节值。
sun.boot.class.path通常對(duì)應(yīng)環(huán)境變量CLASSPATH的路徑。
java.ext.dirs通常對(duì)應(yīng)JAVA_HOME/jre/lib/ext目錄榜聂。
java.class.path對(duì)應(yīng)用戶自身的類路徑搞疗。
類加載到何處
據(jù)可靠情報(bào),jvm由方法區(qū)须肆,堆匿乃,棧,pc寄存器和本地方法棧構(gòu)成豌汇。類加載器的任務(wù)就是將class二進(jìn)制文件加載到方法區(qū)幢炸,供虛擬機(jī)模制出在堆中存放的對(duì)象。
雙親委托機(jī)制
classloader加載類的過程為:
1.檢查被加載類是否被加載拒贱。
2.如果沒有被加載則調(diào)用父classloader加載該類宛徊。
如果1、2不成功逻澳,則仍由自身進(jìn)行類加載闸天。
這種機(jī)制又叫雙親委派機(jī)制。
雙親委派機(jī)制的好處是斜做,避免多個(gè)類加載器加載同一個(gè)類的不同拷貝到內(nèi)存(jvm的方法區(qū))中苞氮。因?yàn)槿绻怉由ClassLoaderA加載,同時(shí)瓤逼,又被ClassLoaderB加載笼吟,這樣,內(nèi)存中就會(huì)存在兩份不同的A的定義抛姑,于是形成A既是ClassLoaderA罩的赞厕,又是ClassLoaderB罩著,造成災(zāi)難性后果定硝。
用戶自定義類的加載順序通常為:
首先調(diào)用AppClassLoader加載類皿桑,AppClassLoader調(diào)用ExtClassLoader,ExtClassLoader調(diào)用BootClassLoader蔬啡,BootClassLoader在sun.boot.class.path尋找改類诲侮,沒找到,加載失斚潴 沟绪;ExtClassLoader也未加載類,失敗空猜,最后由AppClassLoader加載成功绽慈。從這個(gè)加載順序可以看出來恨旱,三個(gè)類加載器的對(duì)類的可見性是不同的。
java中的類是由java的全名以及類的classloader來限定的坝疼。只有當(dāng)二者完全一樣才會(huì)認(rèn)為是同一個(gè)類搜贤。否則是不同的類。因此钝凶,可以定義一個(gè)同名的類仪芒,包名也一樣,只要保證該類被不同的類加載器加載即可耕陷。
當(dāng)前類加載器和線程上下文類加載器
當(dāng)前類加載器
當(dāng)前類加載器是指當(dāng)前方法所在的類使用的類加載器掂名。在程序中使用Class.forName或者Class.getResource抑或Class.class時(shí)就是使用的該類加載器。
線程上下文類加載器
線程上下文類加載器可以不遵循雙親委派機(jī)制哟沫。線程的上下文類加載器有Thread.currentThread().setContextClassLoader()來為當(dāng)前線程設(shè)置線程上下文類加載器饺蔑。如果沒有設(shè)置當(dāng)前線程的上下文類加載器,則繼承父類的上下文類加載器南用。
為什么還需要線程上下文類加載器膀钠?
考慮一種情況,當(dāng)我們的程序必須由jvm的核心代碼去加載第三方類的時(shí)候裹虫。比如jndi肿嘲,jndi的核心是rt.jar包中實(shí)現(xiàn)的,由Bootstrap classloader負(fù)責(zé)加載筑公,但是jndi必須加載第三方廠商的具體的jndi實(shí)現(xiàn)雳窟,這個(gè)時(shí)候調(diào)用Bootstrap加載只對(duì)其子類加載器可見的類,就會(huì)出現(xiàn)失敗匣屡。這個(gè)時(shí)候就可以使用線程上下文類加載器封救。