插件化學(xué)習(xí) - 基礎(chǔ)知識

Java中的ClassLoader

ClassLoader 中與加載類相關(guān)的方法:

方法 說明
getParent() 返回該類加載器的父類加載器
loadClass(String name) 加載名稱為 name的類贷屎,返回的結(jié)果是 java.lang.Class類的實例。
findClass(String name) 查找名稱為 name的類,返回的結(jié)果是 java.lang.Class類的實例。
findLoadedClass(String name) 查找名稱為 name的已經(jīng)被加載過的類,返回的結(jié)果是 java.lang.Class類的實例乡括。
defineClass(String name, byte[] b, int off, int len) 把字節(jié)數(shù)組 b中的內(nèi)容轉(zhuǎn)換成 Java 類,返回的結(jié)果是 java.lang.Class類的實例智厌。這個方法被聲明為 final的诲泌。
resolveClass(Class<?> c) 鏈接指定的 Java 類。

類加載器的樹狀組織結(jié)構(gòu)

Java 中的類加載器大致可以分成兩類铣鹏,一類是系統(tǒng)提供的敷扫,另外一類則是由 Java 應(yīng)用開發(fā)人員編寫的。系統(tǒng)提供的類加載器主要有下面三個:

  • 引導(dǎo)類加載器(bootstrap class loader):它用來加載 Java 的核心庫诚卸,是用原生代碼來實現(xiàn)的葵第,并不繼承自 java.lang.ClassLoader绘迁。
  • 擴展類加載器(extensions class loader):它用來加載 Java 的擴展庫。Java 虛擬機的實現(xiàn)會提供一個擴展庫目錄卒密。該類加載器在此目錄里面查找并加載 Java 類缀台。
  • 系統(tǒng)類加載器(system class loader):也稱為應(yīng)用類加載器,它的父加載器為擴展類加載器哮奇。它從環(huán)境變量classpath或者系統(tǒng)屬性java.class.path所指定的目錄中加載類膛腐,它是用戶自定義的類加載器的默認(rèn)父加載器。系統(tǒng)類加載器是純Java類屏镊,是java.lang.ClassLoader類的子類依疼。

父子加載器并非繼承關(guān)系,也就是說子加載器不一定是繼承了父加載器而芥。

類加載器樹狀組織結(jié)構(gòu)示意圖

雙親委托模式

通俗的講,就是某個特定的類加載器在接到加載類的請求時膀值,首先將加載任務(wù)委托給父類加載器棍丐,依次遞歸,如果父類加載器可以完成類加載任務(wù)沧踏,就成功返回歌逢;只有父類加載器無法完成此加載任務(wù)時,才自己去加載翘狱。

  1. 因為這樣可以避免重復(fù)加載秘案,當(dāng)父親已經(jīng)加載了該類的時候,就沒有必要子ClassLoader再加載一次潦匈。
  2. 考慮到安全因素阱高,我們試想一下,如果不使用這種委托模式茬缩,那我們就可以隨時使用自定義的String來動態(tài)替代java核心api中定義類型赤惊,這樣會存在非常大的安全隱患,而雙親委托的方式凰锡,就可以避免這種情況未舟,因為String已經(jīng)在啟動時被加載,所以用戶自定義類是無法加載一個自定義的ClassLoader掂为。

Android中的ClassLoader

JVM中ClassLoader通過defineClass方法加載jar里面的Class裕膀,而Android中這個方法被棄用了。

@Deprecated
protected final Class<?> defineClass(byte[] b, int off, int len)
    throws ClassFormatError {
    throw new UnsupportedOperationException("can't load this type of class file");
}

取而代之的是loadClass方法

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException {
        // First, check if the class has already been loaded
        Class c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
            }
        }
        return c;
}

DexClassLoader與PathClassLoader

 /**
     * dexPath:被解壓的apk路徑勇哗,不能為空昼扛。

     optimizedDirectory:解壓后的.dex文件的存儲路徑,不能為空智绸。這個路徑強烈建議使用應(yīng)用程序的私有路徑野揪,不要放到sdcard上访忿,否則代碼容易被注入攻擊。

     libraryPath:os庫的存放路徑斯稳,可以為空海铆,若有os庫,必須填寫挣惰。

     parent:父親加載器卧斟,一般為context.getClassLoader(),使用當(dāng)前上下文的類加載器。
     */
class DexClassLoader extends BaseDexClassLoader {
    public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
}
class PathClassLoader extends BaseDexClassLoader {
    public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);
    }

    public PathClassLoader(String dexPath, String libraryPath, ClassLoader parent) {
        super(dexPath, null, libraryPath, parent);
    }
}

這兩者只是簡單的對BaseDexClassLoader做了一下封裝憎茂,具體的實現(xiàn)還是在父類里珍语。
但是兩者還是有區(qū)別的,PathClassLoader的optimizedDirectory只能是null
optimizedDirectory是用來緩存我們需要加載的dex文件的竖幔,并創(chuàng)建一個DexFile對象板乙,如果它為null,那么會直接使用dex文件原有的路徑來創(chuàng)建DexFile對象拳氢。
DexClassLoader可以指定自己的optimizedDirectory募逞,所以它可以加載外部的dex,因為這個dex會被復(fù)制到內(nèi)部路徑的optimizedDirectory馋评;而PathClassLoader沒有optimizedDirectory放接,所以它只能加載內(nèi)部的dex,這些大都是存在系統(tǒng)中已經(jīng)安裝過的apk里面的留特。

  1. DexClassLoader:可以加載jar/apk/dex纠脾,可以從SD卡中加載未安裝的apk;
  2. PathClassLoader:要傳入系統(tǒng)中apk的存放Path蜕青,所以只能加載已經(jīng)安裝的apk文件苟蹈;

參考鏈接:
深入探討 Java 類加載器
Android插件化學(xué)習(xí)之路(二)之ClassLoader完全解析

加載類的過程

java.lang.Object
? java.lang.ClassLoader
? dalvik.system.BaseDexClassLoader
? dalvik.system.DexClassLoader / dalvik.system.PathClassLoader

  1. Android中,ClassLoader用loadClass方法來加載我們需要的類
  2. loadClass方法調(diào)用了findClass方法市咆,而BaseDexClassLoader重載了這個方法
  3. 結(jié)果還是調(diào)用了DexPathList的findClass
  4. 最后調(diào)用了Native方法defineClass加載類

調(diào)用.dex中的代碼

Java程序中汉操,JVM虛擬機是通過類加載器ClassLoader加載.jar文件里面的類的。Android也類似蒙兰,不過android用的是Dalvik/ART虛擬機磷瘤,不是JVM,也不能直接加載.jar文件搜变,而是加載dex文件采缚。

先要通過Android SDK提供的DX工具把.jar文件優(yōu)化成.dex文件,然后Android的虛擬機才能加載挠他。注意扳抽,有的Android應(yīng)用能直接加載.jar文件,那是因為這個.jar文件已經(jīng)經(jīng)過優(yōu)化,只不過后綴名沒改(其實已經(jīng)是.dex文件)贸呢。

調(diào)用普通的邏輯代碼可以通過下面兩種方式:

  1. 使用DexClassLoader加載進來的類镰烧,我們本地并沒有這些類的源碼,所以無法直接調(diào)用楞陷,不過可以通過反射的方法調(diào)用怔鳖。
  2. 畢竟.dex文件也是我們自己維護的,所以可以把方法抽象成公共接口固蛾,把這些接口也復(fù)制到主項目里面去结执,就可以通過這些接口調(diào)用動態(tài)加載得到的實例的方法了。

參考鏈接:
Android動態(tài)加載dex技術(shù)初探
Android插件化學(xué)習(xí)之路(三)之調(diào)用外部.dex文件中的代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末艾凯,一起剝皮案震驚了整個濱河市献幔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌趾诗,老刑警劉巖蜡感,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異恃泪,居然都是意外死亡铸敏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門悟泵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人闪水,你說我怎么就攤上這事糕非。” “怎么了球榆?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵朽肥,是天一觀的道長。 經(jīng)常有香客問我持钉,道長衡招,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任每强,我火速辦了婚禮始腾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘空执。我一直安慰自己浪箭,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布辨绊。 她就那樣靜靜地躺著奶栖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宣鄙,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天袍镀,我揣著相機與錄音,去河邊找鬼冻晤。 笑死苇羡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的明也。 我是一名探鬼主播宣虾,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼温数!你這毒婦竟也來了绣硝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤撑刺,失蹤者是張志新(化名)和其女友劉穎鹉胖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體够傍,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡甫菠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了冕屯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寂诱。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖安聘,靈堂內(nèi)的尸體忽然破棺而出痰洒,到底是詐尸還是另有隱情,我是刑警寧澤浴韭,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布丘喻,位于F島的核電站,受9級特大地震影響念颈,放射性物質(zhì)發(fā)生泄漏泉粉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一榴芳、第九天 我趴在偏房一處隱蔽的房頂上張望嗡靡。 院中可真熱鬧,春花似錦翠语、人聲如沸叽躯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽点骑。三九已至酣难,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間黑滴,已是汗流浹背憨募。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留袁辈,地道東北人菜谣。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像晚缩,于是被迫代替她去往敵國和親尾膊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

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