日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第五章 类加载器ClassLoader源码解析

發布時間:2025/3/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第五章 类加载器ClassLoader源码解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

說明:了解ClassLoader前,先了解?第四章 類加載機制

?

1、ClassLoader作用

  • 類加載流程的"加載"階段是由類加載器完成的。

?

2、類加載器結構

結構:BootstrapClassLoader(祖父)-->ExtClassLoader(爺爺)-->AppClassLoader(也稱為SystemClassLoader)(爸爸)-->自定義類加載器(兒子

關系:看括號中的排位;彼此相鄰的兩個為父子關系,前為父,后為子

2.1、BootstrapClassLoader

  • 下邊簡稱為boot
  • C++編寫
  • 為ExtClassLoader的父類,但是通過ExtClassLoader的getParent()獲取到的是null(在類加載器部分:null就是指boot)
  • 主要加載:E:\Java\jdk1.6\jre\lib\*.jar(最重要的就是:rt.jar)

2.2、ExtClassLoader:

  • 下邊簡稱為ext
  • java編寫,位于sun.misc包下,該包在你導入源代碼的時候是沒有的,需要重新去下
  • 主要加載:E:\Java\jdk1.6\jre\lib\ext\*.jar(eg.dnsns.jar)

2.3、AppClassLoader:

  • 下邊簡稱為app
  • java編寫,位于sun.misc包下
  • 主要加載:類路徑下的jar

2.4、自定義類加載器:

  • 下邊簡稱為custom
  • 自己編寫的類加載器,需要繼承ClassLoader類或URLClassLoader,并至少重寫其中的findClass(String name)方法,若想打破雙親委托機制,需要重寫loadClass方法
  • 主要加載:自己指定路徑的class文件

?

3、全盤負責機制

概念:假設ClassLoaderA要加載class B,但是B引用了class C,那么ClassLoaderA先要加載C,再加載B,"全盤"的意思就是,加載B的類加載器A,也會加載B所引用的類

?

4、雙親委托機制

這也是類加載器加載一個類的整個過程

過程:假設我現在從類路徑下加載一個類A,

1)那么app會先查找是否加載過A,若有,直接返回;

2)若沒有,去ext檢查是否加載過A,若有,直接返回;

3)若沒有,去boot檢查是否加載過A,若有,直接返回;

4)若沒有,那就boot加載,若在E:\Java\jdk1.6\jre\lib\*.jar下找到了指定名稱的類,則加載,結束;

5)若沒找到,boot加載失敗;

6)ext開始加載,若在E:\Java\jdk1.6\jre\lib\ext\*.jar下找到了指定名稱的類,則加載,結束;

7)若沒找到,ext加載失敗;

8)app加載,若在類路徑下找到了指定名稱的類,則加載,結束;

9)若沒有找到,拋出異常ClassNotFoundException

注意:

  • 在上述過程中的1)2)3)4)6)8)后邊,都要去判斷是否需要進行"解析"過程 ("解析"見 第四章 類加載機制)
  • 類的加載過程只有向上的雙親委托,沒有向下的查詢和加載,假設是ext在E:\Java\jdk1.6\jre\lib\ext\*.jar下加載一個類,那么整個查詢與加載的過程與app無關。
  • 假設A加載成功了,那么該類就會緩存在當前的類加載器實例對象C中,key是(A,C)(其中A是類的全類名,C是加載A的類加載器對象實例),value是對應的java.lang.Class對象
  • 上述的1)2)3)都是從相應的類加載器實例對象的緩存中進行查找
  • 進行緩存的目的是為了同一個類不被加載兩次
  • 使用(A,C)做key是為了隔離類,假設現在有一個類加載器B也加載了A,key為(A,B),則這兩個A是不同的A。這種情況怎么發生呢?
    • 假設有custom1、custom2兩個自定義類加載器,他們是兄弟關系,同時加載A,這就是有可能的了

總結

  • 從底向上檢查是否加載過指定名稱的類從頂向下加載該類。(在其中任何一個步驟成功之后,都會中止類加載過程)
  • 雙親委托的好處:假設自己編寫了一個java.lang.Object類,編譯后置于類路徑下,此時在系統中就有兩個Object類,一個是rt.jar的,一個是類路徑下的,在類加載的過程中,當要按照全類名去加載Object類時,根據雙親委托,boot會加載rt.jar下的Object類,這是方法結束,即類路徑下的Object類就沒有加載了。這樣保證了系統中類不混亂。

?

5、源代碼

1 /** 2 * 根據指定的binary name加載class。 3 * 步驟: 4 * 假設我現在從類路徑下加載一個類A, 5 * 1)那么app會先查找是否加載過A(findLoadedClass(name)),若有,直接返回; 6 * 2)若沒有,去ext檢查是否加載過A(parent.loadClass(name, false)),若有,直接返回; 7 * findBootstrapClassOrNull(name) 3)4)5)都是這個方法 8 * 3)若沒有,去boot檢查是否加載過A,若有,直接返回; 9 * 4)若沒有,那就boot加載,若在E:\Java\jdk1.6\jre\lib\*.jar下找到了指定名稱的類,則加載,結束; 10 * 5)若沒找到,boot加載失敗; 11 * findClass(name) 6)7)8)9)都是這個方法 12 * 在findClass中調用了defineClass方法,該方法會生成當前類的java.lang.Class對象 13 * 6)ext開始加載,若在E:\Java\jdk1.6\jre\lib\ext\*.jar下找到了指定名稱的類,則加載,結束; 14 * 7)若沒找到,ext加載失敗; 15 * 8)app加載,若在類路徑下找到了指定名稱的類,則加載,結束; 16 * 9)若沒有找到,拋出異常ClassNotFoundException 17 * 注意:在上述過程中的1)2)3)4)6)8)后邊,都要去判斷是否需要進行"解析"過程 18 */ 19 protected synchronized Class<?> loadClass(String name, boolean resolve) 20 throws ClassNotFoundException { 21 Class c = findLoadedClass(name);//檢查要加載的類是不是已經被加載了 22 if (c == null) {//沒有被加載過 23 try { 24 if (parent != null) { 25 //如果父加載器不是boot,遞歸調用loadClass(name, false) 26 c = parent.loadClass(name, false); 27 } else {//父加載器是boot 28 /* 29 * 返回一個由boot加載過的類;3) 30 * 若沒有,就去試著在E:\Java\jdk1.6\jre\lib\*.jar下查找 4) 31 * 若在bootstrap class loader的查找范圍內沒有查找到該類,則返回null 5) 32 */ 33 c = findBootstrapClassOrNull(name); 34 } 35 } catch (ClassNotFoundException e) { 36 //父類加載器無法完成加載請求 37 } 38 if (c == null) { 39 //如果父類加載器未找到,再調用本身(這個本身包括ext和app)的findClass(name)來查找類 40 c = findClass(name); 41 } 42 } 43 if (resolve) { 44 resolveClass(c); 45 } 46 return c; 47 } View Code

說明:

  • 該段代碼中引用的大部分方法實質上都是native方法
  • 其中findClass方法的類定義如下: /*** 查找指定binary name的類* 該類應該被ClassLoader的實現類重寫*/protected Class<?> findClass(String name) throws ClassNotFoundException {throw new ClassNotFoundException(name);} View Code
  • 關于findClass可以查看URLClassLoader.findClass(final String name),其中引用了defineClass方法,在該方法中將二進制字節流轉換為了java.lang.Class對象

?

附:關于遞歸

遞歸基于棧實現。

上述的代碼如果不清楚遞歸的意義是看不清的。

解釋:

  • app_loadClass()方法執行到ext_loadClass(),這時候對于app_loadClass()中剩余的findClass()會在棧中向下壓;
  • 然后執行ext_loadClass(),當執行到findBootstrapClassOrNull(name),這時候ext_loadClass()中剩余的findClass()也會從棧頂向下壓,此時ext_loadClass()_findClass()僅僅位于app_loadClass()_findClass()的上方;
  • 然后執行findBootstrapClassOrNull(name),當boot檢測過后并且執行完加載后并且沒成功,boot方法離開棧頂;
  • 然后執行此時棧頂的ext_loadClass()_findClass()
  • 然后執行此時棧頂的app_loadClass()_findClass()

這樣,就完成了雙親委托機制。

遞歸太煩了,實際開發中盡量不要用!

轉載于:https://www.cnblogs.com/java-zhao/p/5201291.html

總結

以上是生活随笔為你收集整理的第五章 类加载器ClassLoader源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。