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

Java 類加載器 深度解析:雙親委派、自定義加載器與熱部署應用

     編輯:Java 相關知識

ClassLoader 是 Java 動態載入類的核心機制,支援熱部署、插件化、代碼熱替換等進階場景。本文系統闡述三大系統類加載器、雙親委派模型、自定義加載器實作與經典應用架構。

一、三大系統類加載器

加載器實現語言加載範圍獲取方式
Bootstrap ClassLoader (啟動類加載器)C++ (VM 內建)JAVA_HOME/lib 下可識別類庫 (rt.jar 等)Java 程式無法直接引用
Extension ClassLoader (擴展類加載器)JavaJAVA_HOME/lib/ext 目錄所有類庫開發者可直接使用
Application ClassLoader (應用/系統類加載器)Java用戶類路徑 (Classpath) 指定類庫ClassLoader.getSystemClassLoader()

Application ClassLoader 由 sun.misc.Launcher$AppClassLoader 實現,getSystemClassLoader() 內部透過 Launcher.getLauncher().getClassLoader() 取得並經 AccessController.doPrivileged 特權初始化。

二、雙親委派模型

雙親委派模型圖

核心原則:類加載請求先委派父加載器,父無法處理時子才嘗試。查找順序:Bootstrap → Extension → Application。優勢:

  • 核心類 (如 java.lang.Object) 永遠由 Bootstrap 載入,防止偽造
  • 類隔離與共享可控 (Tomcat、OSGi 架構基礎)
  • 即使自定義加載器嘗試載入同名核心類,VM 會拋出異常阻止

源碼級解析 (ClassLoader.loadClass)

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    synchronized (getClassLoadingLock(name)) {
        Class c = findLoadedClass(name);  // 1. 檢查已載入
        if (c == null) {
            try {
                if (parent != null)       // 2. 委派父加載器
                    c = parent.loadClass(name, false);
                else
                    c = findBootstrapClassOrNull(name);  // 頂層委派 Bootstrap
            } catch (ClassNotFoundException e) { /* 父找不到 */ }
            if (c == null)                // 3. 父失敗,自行 findClass
                c = findClass(name);
        }
        if (resolve) resolveClass(c);     // 4. 連接階段
        return c;
    }
}

開發者可覆寫 loadClass() 或 findClass() 實現自定義邏輯。

三、自定義類加載器實戰

public class ClassLoadDemo {
    public static void main(String[] args) throws Exception {
        ClassLoader customLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                try {
                    String classFile = name.substring(name.lastIndexOf('.')+1) + ".class";
                    InputStream is = getClass().getResourceAsStream(classFile);
                    if (is == null) return super.loadClass(name);
                    byte[] bytes = new byte[is.available()];
                    is.read(bytes);
                    return defineClass(name, bytes, 0, bytes.length);
                } catch (IOException e) {
                    throw new ClassNotFoundException(name);
                }
            }
        };

        String className = "com.yuanhh.classloader.ClassLoadDemo";
        Class<?> clazz = customLoader.loadClass(className);
        Object obj = clazz.newInstance();
        System.out.println(obj.getClass());  // class com.yuanhh.classloader.ClassLoadDemo
        System.out.println(obj instanceof com.yuanhh.classloader.ClassLoadDemo);  // false!
    }
}

關鍵驗證

輸出 false 證明:同一 Class 文件經不同加載器載入,屬於不同類型。obj 由自定義加載器載入 (ClassLoadDemo$1),而直接引用的 ClassLoadDemo.class 由系統加載器載入 (AppClassLoader),instanceof、equals() 等判斷均基於加載器身份。

四、經典應用場景

  • Tomcat:多層加載器架構實現 WebApp 類庫隔離、共享庫複用、容器安全隔離、JSP 熱替換
  • OSGi (Open Service Gateway Initiative):Java 動態模塊化標準,Eclipse IDE 即基於此,實現 Bundle 級類隔離與動態安裝/更新/協作
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved