【JAVA筆記——術】Java ClassLoader類加載機制詳解

Java ClassLoader

三種類加載器

WIki : Java_Classloader

JAVA類加載器實現了一部分 JRE加載JAVA CLASSES到 JVM 的功能。

ClssLoader 實現了懶加載,並且使得JVM不必關心加載文件以及所使用的文件系統。

類加載器雖然只用於實現類的加載動作,但它在JAVA程序中所起到的作用遠遠不限於類加載階段。對於任意一個類,都需要有由加載它的類加載器和這個類本身一同確立其在JAVA虛擬機中的唯一性,每一個類加載器,都擁有一個獨立的類名稱空間。這意味着唯一確定一個JAVA的類需要確認
JavaClassloader + Java Class 相同。

JVM啓動時,這三種加載器將被啓動:

1 Bootstrap class loader

C++語言實現,是虛擬機自身一部分,其他都是JAVA實現繼承java.lang.ClassLoader。負責加載

雙親委派模型

雙親委派模型Parents Delegation Model

雙親委派模型是通過Composition模式實現
雙親委派模型

雙親委派模型的基本思路是,一個類加載器收到了類加載請求,自己不會加載,而是調用父類加載器去完成

sun.misc.Launcher中繼承關係如下

繼承關係

ClassLoader解釋如下

java.lang.ClassLoader
A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a “class file” of that name from a file system.

ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine’s built-in class loader, called the “bootstrap class loader”, does not itself have a parent but may serve as the parent of a ClassLoader instance.
Class loaders that support concurrent loading of classes are known as parallel capable class loaders and are required to register themselves at their class initialization time by invoking the registerAsParallelCapable() method. Note that the ClassLoader class is registered as parallel capable by default. However, its subclasses still need to register themselves if they are parallel capable.
In environments in which the delegation model is not strictly hierarchical, class loaders need to be parallel capable, otherwise class loading can lead to deadlocks because the loader lock is held for the duration of the class loading process (see loadClass methods).
Normally, the Java virtual machine loads classes from the local file system in a platform-dependent manner. For example, on UNIX systems, the virtual machine loads classes from the directory defined by the CLASSPATH environment variable.
However, some classes may not originate from a file; they may originate from other sources, such as the network, or they could be constructed by an application. The method defineClass converts an array of bytes into an instance of class Class. Instances of this newly defined class can be created using Class.newInstance.

基本可以總結如下:

  1. 類加載器可以直接定位或者生成類信息
  2. 類加載器是通過雙親委派模型加載Delegation Model
  3. 默認的三種加載器都已經實現並行加載,但用戶自定義加載器若需要並行加載,需要自行配置,通過調用registerAsParallelCapable()

ClassLoader.loadClass 源碼如下

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) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // 若果父加載器依然無法加載 在調用本身findClass方法進行類加載
                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;
    }

Class 與 ClassLoader

一個類實例化是被其他的類或方法進行調用,其實際的狀況如下:

ClassLoader loader = new NetworkClassLoader(host, port);
Object main = loader.loadClass("Main", true).newInstance();

類加載器在進行類加載之後,再對類進行實例化。

這時候有個疑問,我們經常獲取的類的Class究竟是什麼?根據源碼定義

Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.

我們可以知道:

  1. Class其實是類在Java虛擬機的實例引用
  2. 枚舉類型實際是一種Class
  3. 註解實際是一種接口
  4. 對象數組實際上也是一種Class,在GetClass之後返回的是 元素類 + 數組長度
  5. 基本類型也是一種Class,但基本類型數組不會有返回結果

通常我們獲取ClassLoader是通過獲取

public ClassLoader getClassLoader() {
    ClassLoader cl = getClassLoader0();
    if (cl == null)
        return null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
    }
    return cl;
}

getClassLoader0()是Jvm本地方法,實際上是獲取當前類加載時的加載器。Class在運行初會加載本地方法集,這部分會在Jvm中實現。Class的構造方法是私有的,只能有JVM在實例化Class的時候進行調用,因此getClassLoader0()實際就是從JVM中獲取加載器相關信息。

private static native void registerNatives();
static {
    registerNatives();
}

/*
 * Private constructor. Only the Java Virtual Machine creates Class objects.
 * This constructor is not used and prevents the default constructor being
 * generated.
 */
private Class(ClassLoader loader) {
    // Initialize final field for classLoader.  The initialization value of non-null
    // prevents future JIT optimizations from assuming this final field is null.
    classLoader = loader;
}
發佈了69 篇原創文章 · 獲贊 51 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章