3.代碼實現自定義類加載器


手把手叫你寫類加載器。

了解了類加載器的雙親委派機制, 也知道了雙親委派機制的原理,接下來就是檢驗我們學習是否扎實了,來自定義一個類加載器

一. 回顧類加載器的原理

還是這張圖,類加載器的入口是c++調用java代碼創建了JVM啟動器,其中的一個啟動器是sun.misc.Launcher啟動器。這個啟動器啟動並加載的AppClassLoader和ExtClassLoader。然后調用launcher.getClassLoader()方法獲取loader對象, loader對象本質是一個ClassLoader,然后調用了ClassLoader的loadClass("...")方法加載類。也是在loadClass("...")方法里實現了雙親委派機制。

詳細原理參考文章:https://www.cnblogs.com/ITPower/p/15363400.html

二、自定義類加載器分析

對於類加載器, 我們知道他的重點是loadClass(...)方法, 里面的雙親委派機制也是在loadClass方法里面實現的. loadClass方法里面實際上去加載類的是findClass()方法. 對於我們自定義的類加載器來說需要做到兩點即可

  1. 這個自定義的類加載器繼承自ClassLoader

  2. 這個類加載器要重寫ClassLoader類中的findClass()方法

另外我們還可以參考AppClassLoader和ExtClassLoader來寫。

三、自定義類加載器實現

下面我自己定義了一個類加載器

第一步:自定義類加載器繼承自ClassLoader抽象類,然后定義一個構造方法, 用來接收要加載的類名

第二步:重寫核心方法findClass(String name)

這里有兩步操作,

第一個是: 從類路徑中讀取要加載類的文件內容, 自定義

第二個是: 調用構造類的方法, 調用的系統的defineClass

接下來看看自定義的loadByte是如何實現的

這里的實現就是找到類, 並且將類的內容讀取出來, 轉換成二進制的字節碼, 返回

最后一部分就是如何調用了.

用類加載器加載類, 然后實例化, 使用反射機制調用User1 的方法sout

package com.lxl.jvm;

public class User1 {
    public void sout() {
        System.out.println("進入到User1");
    }
}

這里面System.out.println(clazz.getClassLoader().getClass().getName()); 獲取當前類的類加載器, 猜一猜這里打印的會是誰?

看到了么? 是AppClassLoader, 為什么呢?

原因是我的項目里已經有一個類User1了

我們自定義類加載器的父類是AppClassLoader. 而程序代碼中的User1剛好是被AppClassLoader加載, 因為找到了,所以就不會再去我們指定的文件夾中查找了

這就是類的雙親委派機制的特點.

那么如果我們將項目中的User1類刪除掉, 這是類加載器是誰呢? 當然就是我們自定義的類加載器了.

那么問題來了, 自定義類加載器的父類為什么是AppClassLoader呢?

四. 分析自定義類加載的父類為什么是appClassLoader?

我們來看一下源碼

我們自定義的類加載器, 繼承自ClassLoader類加載器, 那么在調用自定義類加載器的構造方法之前, 應該先加載父類ClassLoader的無參構造函數.

首先會執行ClassLoader的無參的構造方法.

而無參的構造方法會調用自身的構造方法

里面有一個parent, 我們就是要看看這個parent到底是誰呢. 來看看getSystemClassLoader()方法

之前我們已經研究過getClassLoader()這個方法了, 這里面定義的loadClass是誰呢?就是AppClassLoader.

這就是為什么自定義class類加載器的父類是AppClassLoader的原因了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM