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

Java 類加載器層次與雙親委派模型深度解析:從 Bootstrap 到 OSGi 破壞機制

     編輯:Java 綜合教學

Java 類加載器層次與雙親委派模型深度解析

類加載器是 JVM 實現動態性的基石。本文系統梳理三大系統類加載器層次、獲取方式、雙親委派工作流程、源碼級實現、以及歷史上三次重大「破壞」場景(JNDI、OSGi、熱部署)。

一、JVM 視角的兩類加載器

  • 啟動類加載器:C++ 實現(HotSpot),屬於 JVM 內部,加載 %JAVA_HOME%/lib(如 rt.jar)及 -Xbootclasspath 指定路徑。
  • 其他所有加載器:Java 實現,繼承 java.lang.ClassLoader,獨立於 JVM 外部。

二、三大系統類加載器層次

加載器實現類加載路徑獲取方式
Extension ClassLoadersun.misc.Launcher$ExtClassLoader%JAVA_HOME%/lib/ext、java.ext.dirsClassLoader.getSystemClassLoader().getParent()
Application ClassLoadersun.misc.Launcher$AppClassLoader用戶 classpath(-cp/Manifest)ClassLoader.getSystemClassLoader()(默認)

父子關係:AppClassLoader.parent = ExtClassLoader;ExtClassLoader.parent = null(非 Bootstrap)。Bootstrap 不在 Java 層次體系中,無法直接引用。

三、獲取 ClassLoader 的四種方式

// 1. 當前類的類加載器
this.getClass().getClassLoader();

// 2. 當前線程上下文類加載器(支援 JNDI/SPI)
Thread.currentThread().getContextClassLoader();

// 3. 系統類加載器(AppClassLoader)
ClassLoader.getSystemClassLoader();

// 4. 類字面量 .class 隱含加載器
String.class.getClassLoader(); // 返回 null (Bootstrap)

四、類加載兩種模式

  • 隱式加載:JVM 解析類時發現依賴未加載,自動委派加載(繼承、字段類型、方法簽名)。
  • 顯式加載:代碼主動調用 Class.forName()、ClassLoader.loadClass()、自定義 findClass()。

五、雙親委派模型

1. 工作流程

  1. 收到加載請求,先委派父加載器。
  2. 父加載器遞歸委派至頂層(Bootstrap)。
  3. 父加載器無法加載(搜索範圍無目標類),子加載器嘗試 findClass 加載。

2. 核心優勢

  • 沙箱安全:防止核心庫被惡意替換(如自定義 java.lang.String 無法被 Bootstrap 加載)。
  • 類唯一性:同一全限定名在同一加載器體系中只被加載一次。

3. 源碼實現(java.lang.ClassLoader.loadClass)

protected Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException {
    synchronized (getClassLoadingLock(name)) {
        // 1. 檢查已加載
        Class c = findLoadedClass(name);
        if (c == null) {
            // 2. 委派父加載器
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
                c = findBootstrapClassOrNull(name);
            }
            // 3. 父加載失敗,自身 findClass
            if (c == null) {
                c = findClass(name);
            }
        }
        if (resolve) resolveClass(c);
        return c;
    }
}

六、三次重大「破壞」雙親委派

  1. JDK 1.2 前用戶代碼兼容:早期用戶覆蓋 loadClass,JDK 1.2 引入委派模型時保留向下兼容,建議改寫 findClass。
  2. JNDI/SPI 線程上下文加載器:Bootstrap 加載 JNDI API,但需加載應用 Classpath 下的 SPI 實現(如 JDBC 驅動)。解決:線程綁定 Thread.setContextClassLoader(AppClassLoader),父加載器通過子加載器反向加載。
  3. OSGi 熱部署/模塊化:類加載器不再樹狀,轉為網狀結構。Bundle 之間可見性由導入/導出包聲明控制,支援同一類多版本共存、運行時熱替換。

七、獲取類 Class 對象的四種方式

  1. Class.forName("全限定名")
  2. this.getClass()(實例方法)
  3. String.class(類字面量)
  4. 基本類型包裝類 Integer.TYPE / int.class
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved