類加載機制-Classloader

ClassLoader介紹

ClassLoader在Java 1.0的時候就有了,為了滿足Java Applet運行時遠程加載Java類的需要陨溅。
所謂ClassLoader蒿囤,就是將.java文件編譯之后產(chǎn)生的.class字節(jié)文件加載到運行時數(shù)據(jù)區(qū)(JVM的方法區(qū))中的過程纳令。而這個加載過程一般都是按需加載的,就是第一次用到某Class的時候JVM才會去加載其對應的.class文件。

系統(tǒng)提供三個ClassLoader:

  1. Bootstrap ClassLoader
    負責加載java核心類庫(位于<JAVA_HOME>/jre/lib的內(nèi)容)庆械,由本地代碼(如C)編寫津肛。
  2. Extensions ClassLoader
    負責加載java核心類庫(位于<JAVA_HOME>/jre/ext的內(nèi)容),由sun.misc.Launcher$ExtClassLoader實現(xiàn)搜锰。
  3. System ClassLoader (App ClassLoader)
    負責加載應用類伴郁,一般通過java.class.pathCLASSPATH環(huán)境變量來加載 Java 類,由sun.misc.Launcher$ExtClassLoader實現(xiàn)蛋叼。

自定制類加載器

用戶可通過繼承java.lang.ClassLoader自行實現(xiàn)定制的類加載器焊傅。自定制類加載器可以做如下工作:

  1. 運行時裝載或卸載類剂陡,這常用于:
    實現(xiàn)腳本語言
    用于bean生成器
    允許用戶定義的擴展性
    允許命名空間之間的通信。這是CORBA / RMI協(xié)議的基礎狐胎。
  2. 改變Java字節(jié)碼的裝入鸭栖,例如,可用于Java類字節(jié)碼的加密裝入握巢。
  3. 修改已裝入的字節(jié)碼weaving of aspects when using aspect-oriented programming)晕鹊。

自定制類加載器實現(xiàn)示例

public class FileClassLoader extends ClassLoader { 
 
   private String rootDir; 
 
   public FileClassLoader(String rootDir) { 
       this.rootDir = rootDir; 
   } 
 
   protected Class<?> findClass(String name) throws ClassNotFoundException { 
       byte[] classData = getClassData(name); 
       if (classData == null) { 
           throw new ClassNotFoundException(); 
       } 
       return defineClass(name, classData, 0, classData.length);  
   } 
 
   private byte[] getClassData(String className) { 
       String path = classNameToPath(className); 
       try { 
           InputStream ins = new FileInputStream(path); 
           ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
           int bufferSize = 4096; 
           byte[] buffer = new byte[bufferSize]; 
           int bytesNumRead = 0; 
           while ((bytesNumRead = ins.read(buffer)) != -1) 
               baos.write(buffer, 0, bytesNumRead); 
           return baos.toByteArray(); 
       } catch (IOException e) { 
           e.printStackTrace(); 
       } 
       return null; 
   } 
 
   private String classNameToPath(String className) { 
       return rootDir + File.separatorChar 
               + className.replace('.', '/') + ".class"; 
   } 
}

java.lang.ClassLoader類的方法 loadClass()封裝了前面提到的代理模式的實現(xiàn)。該方法會首先調(diào)用 findLoadedClass()方法來檢查該類是否已經(jīng)被加載過暴浦;如果沒有加載過的話溅话,會調(diào)用父類加載器的 loadClass()方法來嘗試加載該類;如果父類加載器無法加載該類的話歌焦,就調(diào)用 findClass()方法來查找該類飞几。因此,為了保證類加載器都正確實現(xiàn)代理模式独撇,在開發(fā)自己的類加載器時屑墨,最好不要覆寫 loadClass()方法,而是覆寫 findClass()方法纷铣。

雙親委派機制:

某個類加載器接到加載類的請求時绪钥,會遞歸地將請求委托給父類加載器,只有父類加載器無法加載的時候自己才會去加載該類关炼。該機制的作用是防止同一個類被加載多次程腹。
自定製類加載器的雙親是System ClassLoader,System ClassLoader的雙親是Extensions ClassLoader儒拂,Extensions ClassLoader的雙親是Bootstrap ClassLoader寸潦。

Namespace

每個類加載器加載的類都會被分配一個裝載其的ClassLoader對應的唯一namspace。namespace就像一道墻社痛,不同namespace被加載的類彼此之間一般無法交互见转,甚至彼此都不知道彼此的存在。
如果要求某個ClassLoader去加載某個類型蒜哀,最終另外一個被委派的ClassLoader加載并返回了這個類型斩箫,那么這兩個ClassLoader共享該類型。這就是用戶可以無視namespace無障礙調(diào)用java api的原因撵儿。

加載流程

  1. loading
    Classloader通過雙親委派機制查找.class文件(TYPE)并載入
  2. linking 分三步
    2.1. verification
    檢查引入TYPE文件正確性
    2.2. preparation
    給class變量分配內(nèi)存(在方法區(qū))并賦值default value:(boolean:false, int:0, reference:null)
    2.3. resolution
    將symbolic reference轉(zhuǎn)為direct reference 乘客,通常延后觸發(fā)。所謂symbolic reference就是fully qualified name(全限定名)淀歇,拿在com.mylib包下的Utility類來說易核,其全限定名是com.mylib.Utility
  3. initialization
    觸發(fā)代碼提供的賦值語句浪默,通常延后觸發(fā)牡直。

加載流程示例:

public class Hello{
    public int age;
    public String name;
    public static String species;
    
    {
        age = 10;
        name = "Jack";
        System.out.println("Non-static block");
    }
    
    static{
        species = "human";
        System.out.println("Static block");
    }
    
    public Hello(){
        System.out.println("initialization");
    }
    
    public static void testStatic() {
        System.out.println("static method invoke");
    }
    
    public void test() {
        System.out.println("instance method invoke");
    }
}

測試類:

import java.lang.reflect.Method;
public class LoadClass {
    public static void main(String [] args) throws Exception {
        LoadClass lc = new LoadClass();
        ClassLoader cl = lc.getClass().getClassLoader();
        System.out.println(cl.getClass().getName());
        
        Class<Hello> HL = (Class<Hello>) cl.loadClass("Hello");
        System.out.println("Hello loaded");
        
        Method m =HL.getMethod("testStatic", null);
        m.invoke(null, null);
        
        Hello hl = HL.newInstance();
    }
}

Console打印結果:

sun.misc.Launcher$AppClassLoader
Hello loaded
Static block
static method invoke
Non-static block
initialization

由上例看出加載自定義的類的默認ClassLoader是AppClassLoader缀匕。在類Hello被加載結束后并沒有給class變量賦值;在調(diào)用static method的時候static block才被觸發(fā)碰逸;在調(diào)用normal method的時候non-static block才被觸發(fā)乡小。

Reference

https://zh.wikipedia.org/wiki/Java類加載器
https://blog.csdn.net/sureyonder/article/details/5564181
https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市饵史,隨后出現(xiàn)的幾起案子满钟,更是在濱河造成了極大的恐慌,老刑警劉巖约急,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件零远,死亡現(xiàn)場離奇詭異,居然都是意外死亡厌蔽,警方通過查閱死者的電腦和手機牵辣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奴饮,“玉大人纬向,你說我怎么就攤上這事〈鞑罚” “怎么了逾条?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長投剥。 經(jīng)常有香客問我师脂,道長,這世上最難降的妖魔是什么江锨? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任吃警,我火速辦了婚禮,結果婚禮上啄育,老公的妹妹穿的比我還像新娘酌心。我一直安慰自己,他們只是感情好挑豌,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布安券。 她就那樣靜靜地躺著,像睡著了一般氓英。 火紅的嫁衣襯著肌膚如雪侯勉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天债蓝,我揣著相機與錄音壳鹤,去河邊找鬼。 笑死饰迹,一個胖子當著我的面吹牛芳誓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播啊鸭,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼锹淌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了赠制?” 一聲冷哼從身側響起赂摆,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钟些,沒想到半個月后烟号,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡政恍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年汪拥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片篙耗。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡迫筑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宗弯,到底是詐尸還是另有隱情脯燃,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布蒙保,位于F島的核電站辕棚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏邓厕。R本人自食惡果不足惜逝嚎,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望邑狸。 院中可真熱鬧懈糯,春花似錦、人聲如沸单雾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽硅堆。三九已至屿储,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間渐逃,已是汗流浹背够掠。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茄菊,地道東北人疯潭。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓赊堪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親竖哩。 傳聞我的和親對象是個殘疾皇子哭廉,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容