前言
在之前我們給出的方案都是繞過應用加載器的方式,並沒有避免一層一層的委託,那麼有沒有什麼辦法可以繞過這種雙親委託模型呢?
很慶幸,JDK提供的雙親委託機制並非是一個強制的模型,程序員可以對其進行靈活的發揮破環這種委託機制的,比如說熱部署,其實就是不停止服務的情況下,更新JVM中的代碼。
具體實現
以下是具體的實現,繼承上篇文章中的MyClassLoader,重寫loadClass方法。
public class BrokerDelegateClassLoader extends MyClassloader {
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
//1
synchronized (getClassLoadingLock(name)) {
//2
Class<?> clazz = findLoadedClass(name);
//3
if (clazz == null) {
//4
if (name.startsWith("java.") || name.startsWith("javax")) {
try {
clazz = getSystemClassLoader().loadClass(name);
} catch (Exception e) {
//ignore
}
}
} else {
//5
try {
clazz = this.findClass(name);
} catch (ClassNotFoundException e) {
//ignore
}
//6
if (clazz == null) {
if (getParent() != null) {
clazz = getParent().loadClass(name);
} else {
clazz = getSystemClassLoader().loadClass(name);
}
}
}
if (null == clazz) {
throw new ClassNotFoundException("The class " + name + " not fount.");
}
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
}
}
- 根據類的全路徑名稱進行加鎖,確保每一個類在多線程情況下只被加載一次
- 到已加載類的緩存中查看該類是否已經被加載,如果已加載則直接返回。
- 同4
- 若緩存中沒有被加載的類,則需要對其進行首次加載,如果以java和javax開頭的,則直接委託給系統類加載器加載。
- 如果類不是以java和javax開頭的,嘗試用自己的類加載器進行加載。
- 若自定義的加載器沒有完成對類的加載,則委託給父類加載器或者系統類加載器進行加載。
- 經過若干次嘗試後,如果還是無法對類進行加載,則拋出無法找到類的異常。
測試代碼
public class BrokerDelegateClassLoader extends MyClassloader {
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
//1
synchronized (getClassLoadingLock(name)) {
//2
Class<?> clazz = findLoadedClass(name);
//3
if (clazz == null) {
//4
if (name.startsWith("java.") || name.startsWith("javax")) {
try {
clazz = getSystemClassLoader().loadClass(name);
} catch (Exception e) {
//ignore
}
} else {
//5
try {
clazz = this.findClass(name);
} catch (ClassNotFoundException e) {
//ignore
}
//6
if (clazz == null) {
if (getParent() != null) {
clazz = getParent().loadClass(name);
} else {
clazz = getSystemClassLoader().loadClass(name);
}
}
}
}
if (null == clazz) {
throw new ClassNotFoundException("The class " + name + " not found.");
}
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
}
}
可以看到仍然是我們自定義類加載器加載的,既然我們可以通過這種打破雙親委託機制進行類加載,那我們自定義的類加載器能否加載一個和String類全路徑名稱完全一致的class呢?請關注下篇博客。