BootstrapClassLoader (啟動類加載器)
│ C++ 實現,無 Java 引用,getParent() 返回 null
│ 加載:$JAVA_HOME/jre/lib/rt.jar 等核心庫
↓
ExtClassLoader (擴展類加載器)
│ sun.misc.Launcher$ExtClassLoader
│ 加載:$JAVA_HOME/jre/lib/ext/*.jar
↓
AppClassLoader (應用/系統類加載器)
│ sun.misc.Launcher$AppClassLoader
│ 加載:classpath (-cp) 指定路徑
↓
CustomClassLoader (用戶自定義)
│ 繼承 ClassLoader/URLClassLoader
│ 加載:自定義路徑、網絡、加密等特殊來源
核心邏輯在 ClassLoader.loadClass(String name, boolean resolve):
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// 1. 檢查緩存:是否已加載
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
// 2. 委派父加載器(遞歸向上)
c = parent.loadClass(name, false);
} else {
// 3. 父為 null 即 Bootstrap,調用 native 查找
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 父加載器找不到,繼續往下執行
}
// 4. 父加載器都找不到,自己查找 (findClass)
if (c == null) {
c = findClass(name); // 觸發 defineClass 生成 Class 對象
}
}
// 5. 可選:解析階段
if (resolve) {
resolveClass(c);
}
return c;
}
AppClassLoader.loadClass("A")
→ ExtClassLoader.loadClass("A") // 壓棧:App.findClass 待執行
→ Bootstrap.findBootstrapClassOrNull("A") // 壓棧:Ext.findClass 待執行
← Bootstrap 返回 null
← Ext.findClass("A") 執行 → 返回 null
← App.findClass("A") 執行 → 加載成功或拋出 CNFE
(類全名, 加載器實例) 作為 Key,防止重複加載與類身份混淆典型場景:JNDI、JDBC、OSGi、熱部署、代碼熱替換
// 自定義類加載器:重寫 loadClass 而非 findClass
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// 1. 先檢查自己緩存
Class<?> c = findLoadedClass(name);
if (c != null) return c;
// 2. 特定前綴類自己加載(如 com.myapp.hotdeploy.*)
if (name.startsWith("com.myapp.hotdeploy.")) {
c = findClass(name); // 直接調用自己 findClass
} else {
// 3. 其他委派父加載器
c = super.loadClass(name, resolve);
}
return c;
}
}
// findClass 實現邏輯
protected Class<?> findClass(final String name) {
// 1. 將類名轉為路徑:com/example/A.class
String path = name.replace('.', '/').concat(".class");
// 2. 從 URLs 中查找資源
Resource res = ucp.getResource(path, false);
if (res != null) {
// 3. 讀取字節碼
ByteBuffer bb = res.getByteBuffer();
// 4. 定義類 (native)
return defineClass(name, bb, ...);
}
throw new ClassNotFoundException(name);
}