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

JVM 類加載機制深度解析:原理、實現與自定義 ClassLoader 實戰

     編輯:Java 程式設計入門

類加載全生命週期

  1. 加載:尋找並讀取 .class 二進制數據,生成 java.lang.Class 對象
  2. 鏈接
    • 驗證:文件格式、元數據、字節碼語義合法性
    • 準備:為 static 欄位分配內存、賦預設值
    • 解析:符號引用 → 直接引用(可選,延遲到首次使用)
  3. 初始化:執行 <clinit>()(static 初始化塊、static 欄位賦值)

ClassLoader 核心方法

方法職責
loadClass(name, resolve)入口點:檢查緩存 → 委派父加載器 → 自定義查找 → defineClass → resolve
defineClass(bytes)字節碼 → Class 對象,含驗證、解析
findSystemClass(name)從本地路徑(CLASSPATH)加載
resolveClass(Class)觸發鏈接階段
findLoadedClass(name)檢查是否已加載,避免重複

雙親委派模型

類加載體系結構 代理結構

四大標準加載器

加載器父加載器加載來源實現語言
Bootstrapnullsun.boot.class.path (rt.jar 等)C/C++ (JVM 內建)
ExtensionBootstrapjava.ext.dirsJava
System/ApplicationExtensionCLASSPATHJava
AppletSystem網絡 CodeBaseJava

委派流程

// 以 Applet 加載 TestApplet 為例
AppletClassLoader.loadClass("TestApplet")
    → 委派 SystemClassLoader (CLASSPATH 無此類)
    → 委派 ExtensionClassLoader (ext 無此類)
    → 委派 Bootstrap (rt.jar 無此類)
    → 父加載器均失敗,AppletClassLoader 自行從網絡下載 .class
    → 發現父類 java.applet.Applet
    → 再次委派鏈,最終由 Bootstrap 加載 java.applet.Applet
    → 返回已加載的父類 Class 對象

自定義 ClassLoader 實戰範本

public abstract class MultiClassLoader extends ClassLoader {
    private Map cache = new HashMap<>();

    @Override
    public synchronized Class loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        // 1. 檢查緩存
        Class c = cache.get(name);
        if (c != null) return c;

        // 2. 委派系統加載器
        try {
            c = super.findSystemClass(name);
            return c;
        } catch (ClassNotFoundException ignored) {}

        // 3. 自定義來源:資料庫、網絡、加密文件等
        byte[] bytes = loadClassBytes(name); // 抽象方法
        if (bytes == null) throw new ClassNotFoundException();

        // 4. 定義類
        c = defineClass(null, bytes, 0, bytes.length);
        if (c == null) throw new ClassFormatError();

        // 5. 解析與緩存
        if (resolve) resolveClass(c);
        cache.put(name, c);
        return c;
    }

    protected abstract byte[] loadClassBytes(String name);
}

關鍵約束

  • 同一全限定名,同一加載器實例只能返回同一 Class 對象
  • 父子加載器對共享類(父類、介面、簽名類型)必須返回同一對象
  • 已加載類不可更換加載器(getClassLoader() 不可變)

典型應用場景

  • 熱部署/插件系統:隔離插件類庫,支援版本共存
  • 加密類保護:運行時解密字節碼再 defineClass
  • 應用服務器:每個 WebApp 獨立 ClassLoader 實現隔離
  • JDBC 驅動 SPI:ServiceLoader 機制依賴線程上下文加載器
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved