java.lang.ClassLoader與java.net.URLClassLoader學習

第一部分:java.lang.ClassLoader

類加載器(class loader)用來加載 Java 類到 Java 虛擬機中。一般來說,Java 虛擬機使用 Java 類的方式如下:Java 源程序(.java 文件)在經過 Java 編譯器編譯之後就被轉換成 Java 字節代碼(.class 文件)。類加載器負責讀取 Java 字節代碼,並轉換成 java.lang.Class 類的一個實例。每個這樣的實例用來表示一個 Java 類。通過此實例的 newInstance()方法就可以創建出該類的一個對象。實際的情況可能更加複雜,比如 Java 字節代碼可能是通過工具動態生成的,也可能是通過網絡下載的。 基本上所有的類加載器都是 java.lang.ClassLoader 類的一個實例

  1. 構造函數

public abstract class ClassLoader
   
private static native void registerNatives();
    static {
        registerNatives();
    }
    
private ClassLoader(Void unused, ClassLoader parent) {
        this.parent = parent;
        if (ParallelLoaders.isRegistered(this.getClass())) {
            parallelLockMap = new ConcurrentHashMap<>();
            package2certs = new ConcurrentHashMap<>();
            domains =
                Collections.synchronizedSet(new HashSet<ProtectionDomain>());
            assertionLock = new Object();
        } else {
            // no finer-grained lock; lock on the classloader instance
            parallelLockMap = null;
            package2certs = new Hashtable<>();
            domains = new HashSet<>();
            assertionLock = this;
        }
    }


2.loadClass方法,該方法爲類加載器的主要方法,具體代碼如下:


    

 protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
            //1.異步保護,防止重複加載同一個class
        synchronized (getClassLoadingLock(name)) {
            //2.首先,檢查是否類已經被加載過了
            Class<?> c = findLoadedClass(name);
            if (c == null) {
            //2.1如果該類未被加載過
                    //2.1.1 System.nanoTime()這個方法主要是返回一個系統計時器的當前值,以毫微秒爲單位。但是不能用作來計算當前時間,只能通過end-start算出間隔時間
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                    //2.1.2如果有父加載器,即父加載器不爲初始加載器,則遞歸父加載器查看是否加載過
                        c = parent.loadClass(name, false);
                    } else {
                    //2.1.3如果沒有父加載器,即父加載器爲初始加載器,查找類是否加載,具體看方法
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    //2.1.4如果還是沒有該類,則運行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) {
            //解析class,resolve默認爲false
                resolveClass(c);
            }
            return c;
        }
    }


3.getClassLoadingLock(name)方法

 protected Object getClassLoadingLock(String className) {
        Object lock = this;
        if (parallelLockMap != null) {
            Object newLock = new Object();
            lock = parallelLockMap.putIfAbsent(className, newLock);
            if (lock == null) {
                lock = newLock;
            }
        }
        return lock;
    }




4.findLoadedClass(name)方法

   protected final Class<?> findLoadedClass(String name) {
        if (!checkName(name))
            return null;
        return findLoadedClass0(name);
    }

    private native final Class<?> findLoadedClass0(String name);


5.findBootstrapClassOrNull(name)方法

 private Class<?> findBootstrapClassOrNull(String name)
    {
        if (!checkName(name)) return null;

        return findBootstrapClass(name);
    }

    // return null if not found
    private native Class<?> findBootstrapClass(String name);


6.findClass(name)方法,該方法在ClassLoader中沒有具體實現,因此根據不同的情況會重寫該方法進行不同情況的判斷。

 protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }

7.resolveClass(Class<?> c)方法

 protected final void resolveClass(Class<?> c) {
        resolveClass0(c);
    }

    private native void resolveClass0(Class<?> c);

8.defineClass方法,主要是將字節碼class文件進行實例爲Class實例。該方法不可覆蓋,我們在繼承ClassLoader的時候,會重寫findClass方法將相關文件轉換成jvm可識別的Class實例。必須要在重寫的findClass中調用defineClass纔可以完成轉換的邏輯。

    

protected final Class<?> defineClass(String name, byte[] b, int off, int len)
        throws ClassFormatError
    {
        return defineClass(name, b, off, len, null);
    }
 protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                                         ProtectionDomain protectionDomain)
        throws ClassFormatError
    {
        protectionDomain = preDefineClass(name, protectionDomain);
        String source = defineClassSourceLocation(protectionDomain);
        Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
        postDefineClass(c, protectionDomain);
        return c;
    }

9.ClassLoader類的相關測試。



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