類(lèi)加載的過(guò)程:
加載耗帕,鏈接(驗(yàn)證,準(zhǔn)備绘盟,解析)刨沦,初始化
loadClass只做到了加載诗宣。
Java中的類(lèi)加載器包括四類(lèi):
- BootstrapClassLoader:加載java包路徑下的核心類(lèi)庫(kù);
- ExtClassLoader:加載ext路徑下的類(lèi)想诅;
- AppClassLoader:加載程序所在目錄下的類(lèi)召庞;
- 自定義ClassLoader: 自定義加載路徑。
雙親委派的工作流程:
一個(gè)類(lèi)加載器收到了類(lèi)加載的請(qǐng)求来破,它首先不會(huì)自己去嘗試加載這個(gè)類(lèi)篮灼,自底向上的遞歸查詢父加載器是否已經(jīng)加載了這個(gè)類(lèi),如果BootstrapClassLoader返回未加載這個(gè)類(lèi)徘禁,載自頂向下的嘗試加載這個(gè)類(lèi)诅诱。
雙親委派機(jī)制保證了一個(gè)類(lèi)只被加載一次,并且在程序的各種類(lèi)加載器環(huán)境中都能保證是同一個(gè)類(lèi)送朱。
雙親委派.png
雙親委派的實(shí)現(xiàn):
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
破壞雙親委派模型的場(chǎng)景
- 雙親委派模型是1.2引入的娘荡,類(lèi)加載是1.0引入的
- SPI(Service Provider Interface)機(jī)制(JDBC等等)
用JDBC連接的例子來(lái)說(shuō)明,下面調(diào)用getConnection方法來(lái)獲得連接骤菠,我們需要調(diào)用getConnection方法來(lái)加載MySQL的jar包它改,但是我們實(shí)際獲得的初始化的類(lèi)加載器是當(dāng)前類(lèi)的類(lèi)加載器,也就是DriverManager的類(lèi)加載器商乎,DriverManager在 package java.sql; 下,因?yàn)槲覀儷@得的類(lèi)加載器是BootstrapClassLoader祭阀,導(dǎo)致無(wú)法加載MySQL的jar包鹉戚。Java引入了一個(gè)Thread.contextClassLoader,可以任意設(shè)置當(dāng)前線程的ClassLoader來(lái)解決這個(gè)問(wèn)題鲜戒。
DriverManager.getConnection("jdbc://mysql://localhost:3306");