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

ClassLoader 深度解析:類別載入機制、雙親委派模型與自訂載入器實作

     編輯:Java 綜合教學

什麼是 ClassLoader?

ClassLoader(類別載入器) 是 Java 執行環境的核心組件,負責將 .class 位元碼從各種來源(檔案系統、網路、JAR、資料庫等)讀入 JVM 記憶體,轉換為 java.lang.Class 物件,供程式執行使用。Java 的動態載入特性、熱部署、模組化框架(如 OSGi、Spring 模組)皆建立於此機制之上。

核心職責

  1. 載入:尋找並讀取類別二進位資料。
  2. 連結:驗證、準備(靜態欄位賦初值)、解析(符號參考轉直接參考)。
  3. 初始化:執行 <clinit>() 方法(靜態區塊、靜態欄位賦值)。

誰來載入 ClassLoader 自己?

這是個經典「雞生蛋、蛋生雞」問題。JVM 啟動時會建立三層內建載入器(Bootstrap → Extension → Application),它們由 C++ 實作(Bootstrap)或 Java 實作但由上層載入,形成啟動鏈:

  • Bootstrap ClassLoader:C++ 實作,載入 <JAVA_HOME>/lib 核心類別(rt.jar 等),無父載入器。
  • Extension ClassLoader:由 Bootstrap 載入,負責 <JAVA_HOME>/lib/ext 或 java.ext.dirs 指定目錄。
  • Application ClassLoader:由 Extension 載入,載入 classpath 指定的應用程式類別,也是 ClassLoader.getSystemClassLoader() 返回的實例。

使用者自訂 ClassLoader 必須繼承 java.lang.ClassLoader,其父載入器預設為 Application ClassLoader,形成樹狀階層。

雙親委派模型

載入請求先向上委派給父載入器,只有父載入器找不到時,子載入器才嘗試自行載入。優點:

  • 避免核心類別被惡意覆寫(安全性)。
  • 確保同一類別在 JVM 中唯一(避免重複載入)。
protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
    synchronized (getClassLoadingLock(name)) {
        Class c = findLoadedClass(name);
        if (c == null) {
            try {
                if (parent != null) c = parent.loadClass(name, false);
                else c = findBootstrapClassOrNull(name);
            } catch (ClassNotFoundException e) { /* ignore */ }
            if (c == null) c = findClass(name); // 自己載入
        }
        if (resolve) resolveClass(c);
        return c;
    }
}

打破雙親委派的場景

  • JNDI、JDBC、Logging:核心庫需呼叫應用層實作(SPI 機制),使用 Thread.currentThread().getContextClassLoader() 反向載入。
  • 熱部署/模組化:Tomcat、OSGi、Spring Boot DevTools 透過自訂載入器隔離類別命名空間,實現多版本共存與動態更新。

自訂 ClassLoader 實作範本

public class MyClassLoader extends ClassLoader {
    private final String basePath;

    public MyClassLoader(String basePath) {
        this.basePath = basePath;
    }

    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name);
        if (classData == null) throw new ClassNotFoundException(name);
        return defineClass(name, classData, 0, classData.length);
    }

    private byte[] loadClassData(String name) {
        // 從檔案、網路、資料庫等讀取位元碼
        String path = basePath + name.replace('.', '/') + ".class";
        try (InputStream is = new FileInputStream(path)) {
            return is.readAllBytes();
        } catch (IOException e) {
            return null;
        }
    }
}

實戰應用場景

  • 加密類別檔防反編譯:載入時解密位元碼。
  • 插件系統:隔離插件依賴,避免版本衝突。
  • 動態代理生成:ByteBuddy、CGLIB 等庫底層即用自訂載入器定義新類別。

掌握 ClassLoader 機制,是進階 Java 開發、框架原理分析與疑難雜症排查的關鍵鑰匙。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved