classLoader如何加載class【雙親委託模式】

ClassLoader【雙親委託模式進行類加載】

它是用來加載Class文件到JVM(Java Virtual Machine(Java虛擬機)的縮寫)。
以供程序使用的。我們知道,Java程序可以動態加載類定義,而這個動態加載的機制就是
通過ClassLoader來實現的。
其中有一個ClassLoader不是用Java語言所編寫的,而是JVM實現的一部分,這個
ClassLoader就是bootstrap classloader(啓動類加載器),這個ClassLoader
在JVM運行的時候加載Java核心的API以滿足Java程序最基本的需求,其中就包括用戶自
定義的ClassLoader,這裏所謂的用戶自定義是指通過Java程序實現的ClassLoader,
一個是ExtClassLoader,這個ClassLoader是用來加載Java的擴展API的,也就是
/lib/ext中的類。另一個是AppClassLoader,這個ClassLoader是用來加載用戶機器
上CLASSPATH設置目錄中的class的,通常在沒有指定ClassLoader的情況下,我們自
定義的類就由該ClassLoader進行加載。
當運行一個程序的時間,JVM啓動,運行bootstrap classloader,該ClassLoader加
載Java核心API(ExtClassLoader和APPClassLoader也在此時被加載),然後調用
ExtClassLoader加載擴展API,最後APPClassLoader加載CLASSPATH目錄下定義的
class,這就是一個程序最基本的加載流程。
每一個自定義ClassLoader都必須繼承ClassLoader這個抽象類,而每個ClassLoader
都會有一個parent ClassLoader,我們可以看一下ClassLoader這個抽象類中有一個
getParent()方法,這個方法用來返回當前ClassLoader的parent,注意,這個parent
不是指定的被繼承的類,而是在實例化該ClassLoader時指定的一個ClassLoader,如果
這個parent爲null,那麼就默認該ClassLoader的parent是bootstrap classloa-
der,這個parent有什麼用呢?

我們可以考慮這樣一種情況,假設我們自定義了一個ClientDefClassLoader,我們使用
這個自定義的ClassLoader加載java.lang.String,那麼這裏String是否會被這個
ClassLoader加載呢?事實上,java.lang.String這個類並不是被這個ClientDef-
ClassLoader加載,而是由bootstrap classloader進行加載,爲什麼會這樣?實際
上這就是雙親委託模式的原因,因爲在任何自定義ClassLoader加載一個類之前,它都會
先委託它的父親ClassLoader進行加載,只有當父親ClassLoader無法加載成功後,纔會
由自己加載,在上面這個例子裏,因爲java.lang.String是屬於Java核心API的一個類,
所以當使用ClientDefClassLoader加載它的時候,該ClassLoader會先委託他的父親
ClassLoader進行加載,當ClassLoader的parent爲null時,ClassLoader的parent
就是bootstrap classloader,所以在ClassLoader的最頂層就是bootstrap 
classloader,因此最終委託到bootstrap classloader的時候,bootstrap 
classloader就會返回String的Class。

下面我們看一下ClassLoader中的一段源碼:

public class Snippet{
 
    protected synchronized Class loadClass(String name,boolean resolve) throws
        ClassNotFoundException{
        //首先檢查該name指定的class是否被加載
        Class c = findLoadedClass(name);
        if(c==null){
            try{
                if(parent!=null){
                //如果parent不爲null,則調用parent的loadClass進行加載
                c=parent.loadClass(name,false);
                }else{
                //如果parent爲null,則調用BootstrapClassLoader進行加載
                c=findBootstrapClass0(name);
                }
       }catch(ClassNotFoundException e){
            //如果仍然無法加載成功,則調用自身的findClass進行加載
            c=findClass(name);
        }
  }
        if(resolve){resolveClass(c);}
        return c;
 }             
}

從上面的一段代碼,我們可以看出一個類加載的大概過程,與我們剛開始所舉的例子是一樣的,而我們要實現一個自定義類的時間,只需要實現findClass方法即可。
爲什麼要使用這種雙親委託模式呢?
1:避免重複加載,當父親已經加載過該類的時候,就沒有必要再加載一次了
2:考慮到安全因素,試想一下,如果不使用這種模式,我們可以隨時的用自定的String來動態替代java核心API中定義類型,這樣存在非常大的安全隱患

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