JVM學習(七)——JVM中的類加載器

簡介

所有的類都由類加載器加載,加載的作用就是將 .class文件加載到內存。

JVM 中內置了三個重要的 ClassLoader,除了 BootstrapClassLoader 其他類加載器均由 Java 實現且全部繼承自java.lang.ClassLoader:

  1. BootstrapClassLoader(啓動類加載器) :最頂層的加載類,由C++實現,負責加載 %JAVA_HOME%/lib目錄下的jar包和類或者或被 -Xbootclasspath參數指定的路徑中的所有類。
  2. ExtensionClassLoader(擴展類加載器):主要負責加載目錄 %JRE_HOME%/lib/ext 目錄下的jar包和類,或被 java.ext.dirs 系統變量所指定的路徑下的jar包。
  3. AppClassLoader(應用程序類加載器) :面向我們用戶的加載器,負責加載當前應用classpath下的所有jar包和類。

雙親委派模型

每一個類都有一個對應它的類加載器。系統中的 ClassLoder 在協同工作的時候會默認使用 雙親委派模型

雙親委派模型

  • 在類加載的時候,系統會首先判斷當前類是否被加載過。已經被加載的類會直接返回,否則纔會嘗試加載。
  • 加載的時候,首先會把該請求委派該父類加載器的 loadClass() 處理,因此所有的請求最終都應該傳送到頂層的啓動類加載器 BootstrapClassLoader 中。當父類加載器無法處理時,才由自己來處理。當父類加載器爲null時,會使用啓動類加載器 BootstrapClassLoader 作爲父類加載器。

通過雙親委派模型確認所有類只加載一次,
底部類加載器判斷一個類是否被加載,如果加載就直接返回。
如果沒有被加載,把請求交給父類加載器,讓在判斷父類加載器是否加載過該類,如果父類加載器也沒有加載過該類,然後再把請求向上傳遞,一直到BootstrapClassLoader類加載器。
然後從BootstrapClassLoader類加載器開始加載該類,如果能加載就加載,如果不能加載,就交給子類加載器加載,依次往下,如果到最低層還沒有加載到該類,就報類找不到異常。

在這裏插入圖片描述

AppClassLoader的父類加載器爲ExtClassLoader ,ExtClassLoader的父類加載器爲null,null並不代表ExtClassLoader沒有父類加載器,而是 Bootstrap ClassLoader 。

雙親委派模型實現源碼分析

雙親委派模型的實現代碼非常簡單,邏輯非常清晰,都集中在 java.lang.ClassLoader 的 loadClass() 中。

private final ClassLoader parent; 
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{

        synchronized (getClassLoadingLock(name)) {
            // 首先,檢查請求的類是否已經被加載過
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {//父加載器不爲空,調用父加載器loadClass()方法處理
                        c = parent.loadClass(name, false);
                    } else {//父加載器爲空,使用啓動類加載器 BootstrapClassLoader 加載
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                   //拋出異常說明父類加載器無法完成加載請求
                }

                if (c == null) {
                    long t1 = System.nanoTime();
                    //自己嘗試加載
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
	}

雙親委派模型的好處:

雙親委派模型保證了Java程序的穩定運行,可以避免類的重複加載(JVM 區分不同類的方式不僅僅根據類名,相同的類文件被不同的類加載器加載產生的是兩個不同的類),也保證了 Java 的核心 API 不被篡改。如果沒有使用雙親委派模型,而是每個類加載器加載自己的話就會出現一些問題,比如我們編寫一個稱爲 java.lang.Object 類的話,那麼程序運行的時候,系統就會出現多個不同的 Object 類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章