首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

ClassLoader 源碼級深度解析:雙親委派模型、全盤負責機制與自定義類加載器實戰

     編輯:Java 綜合教學

類加載器層級架構

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;
    }
}

URLClassLoader 核心流程

// 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);
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved