記錄學習java 加載器學習所獲心得,逐步記錄了解java加載器的過程。為了知悉android 插件化的實現原理,從而需要從頭了解android加載apk,以及基礎的java類加載的加載過程情況,為方便記錄和記憶,故此將學習了解的過程記錄成文字,以下文字記錄部分可能來自與多個來源,主體以Java源碼和IBM開發者博客有關java加載技術的博客為主。
Java 類的加載過程
慣性思維,想要了解apk的加載過程,我希望先簡單知道以下Java中對類加載過程的處理(Java一直都是android的官方開發語言,雖然現在kotlin也是,但原理不變)。首先需要了解Java 類在jvm中的加載過程,基本的流程如下:
裝載
裝載是通過已經編譯生成的class文件的位置查找文件獲取其字節流導入class文件,并將其轉換成一個Class類的一個實例,將類的實例存放在jvm的堆區,獲取裝載類的信息到方法區(屬于jvm的內存區域的一種,主要用于存放類的字段、方法,常量池等信息),這里就是負責處理完成類的加載的過程,主要是由ClassLoader及其子類完成。鏈接
其主要功能就是對類信息格式進行校驗,分配方法區域的類變量的初始值(并非設置的初始化數值,而是初始“0”值)并將類的引用指向對應類的實例。其內部分為三個過程:校驗 —>準備—>解析。執行順序為既定的。初始化
初始化類的靜態變量和靜態代碼塊(相對于鏈接中的準備階段,將已經“初始化”的靜態數據進行真正的初始化).類的初始化情況:
1)遇到類的創建指令New指令
2)java主運行程序的入口類的實例
3)通過反射創建類(newInstance、forClass等)
4)子類初始化觸發父類的初始化操作
5)java 1.7動態類型初始化使用和卸載
對創建java對象的操作以及java回收機制對jvm的自動回收卸載。
Java 類加載器
如上,對于java類的加載使用,屬于應用層程序員可控過程就只有類的加載過程,通過指定類的加載器來加載我們的類信息,首先通過java的源碼文檔來簡單了解一下類加載的介紹。類加載器位置:
java.lang.ClassLoader.java
文檔介紹為:類加載器主要負責加載類的對象,通過給定一個類的“二進制名稱”,那么類加載器會嘗試定位或身成類定義的數據信息。一般策略是將二進制名稱轉化為一個文件的名稱并加載該類文件的二進制數據。數組類型的類的對象并不是由類加載器創建,而是java 運行時根據需要自動創建.數組類型的加載器由Class.getClassLoader()返回.該加載器與其元素類型的類加載器是相同的;如果該元素類型是基本類型,則該數組類沒有類加載器。
程序可以通過繼承ClassLoader的子類來擴展動態加載方式.類加載器支持雙親委托模型(通過委托父類查找資源的方式進行操作)查找類或類的資源.虛擬機的內置類加載器(稱為 “bootstrap class loader”)本身沒有父類加載器,但是可以將它用作 ClassLoader 實例的父類加載器……
如上,為部分對于ClassLoader的介紹文字.對于通用類加載器通常將其分為四個類型,如下介紹:
引導型類加載器(bootstrap)
該類加載器并沒有父類類加載器,具體實現是通過原生代碼實現(平臺相關的),用于加載Java的核心代碼,無法直接通過代碼使用.擴展型類加載器
它用來加載 Java 的擴展庫。Java 虛擬機的實現會提供一個擴展庫目錄。該類加載器在此目錄里面查找并加載 Java 類。android中相當于java.lang.BootClassLoader系統類加載器(system class loader)
它根據 Java 應用的類路徑(CLASSPATH)來加載 Java 類。一般來說,Java 應用的類都是由它來完成加載的。可以通過 ClassLoader.getSystemClassLoader()獲取。android 中相當與dalvik.system.PathClassLoader.線程上下文類加載器
用于設置和獲取線程上下文的類加載器,若是未曾設置該加載器,線程上下文類加載器將繼承自父線的上下文類加載器,而Java應用初始線程上下文類加載器為系統加載器,android中也就是繼承自BaseDexClassLoader的子類加器PathClassLoader或者DexClassLoader加載器.基于Android 平臺對于以上的加載器做一個簡單的代碼測試如下:
var loader=classLoaderwhile (loader != null) {println("加載器類型:${loader.toString()}")loader = loader.parent}//輸出結果如下10-30 17:55:05.964 23338-23338/com.enjoytoday I/System.out: 加載器類型:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.enjoytoday-2/base.apk", zip file "/data/app/com.enjoytoday-2/split_lib_dependencies_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_0_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_1_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_2_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_3_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_4_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_5_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_6_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_7_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_8_apk.apk", zip file "/data/app/com.enjoytoday-2/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/data/app/com.enjoytoday-2/lib/arm64, /system/fake-libs64, /data/app/com.enjoytoday-2/base.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_dependencies_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_0_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_1_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_2_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_3_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_4_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_5_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_6_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_7_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_8_apk.apk!/lib/arm64-v8a, /data/app/com.enjoytoday-2/split_lib_slice_9_apk.apk!/lib/arm64-v8a, /system/lib64, /vendor/lib64, /system/vendor/lib64, /product/lib64]]]
10-30 17:55:05.964 23338-23338/com.enjoytoday I/System.out: 加載器類型:java.lang.BootClassLoader@d725e7d
Android 中的類加載器
Android 中的虛擬機是由dalvik來實現,dalvik并非典型的Java虛擬機。因此,其類的加載器和標準有所不同,對于dalvik而言,其并不可以直接識別加載class文件,而是對class打包成的dex文件進行加載。因此,Android源碼對ClassLoader進行處理,并派生一個子類BaseDexClassLoader,其本質類似于jvm中的ClassLoader,確切的說可以說是一個Dex加載器。
基于Android 平臺的類加載器結構如下:
BootClassLoader
是屬于ClassLoader的一個內部類,不可直接使用,每個ClassLoader中都存在一個parent(ClassLoader類型),父類加載器,而BootClassLoader屬于最頂層的parent.URLClassLoader
這個是一個輸入jar的加載器,在java中支持在線或本地指定jar文件來加載jar包,但由于android中dalvik并不可以識別class或者jar,只能加載dex,所以并不可以直接使用URLClassLoader來加載jar文件BaseDexClassLoader
這個屬于加載dex文件的加載器的實現,具體的加載邏輯在其中實現
PathClassLoader
繼承自BaseDexClassLoader,為默認apk安裝使用的類加載器,會自動尋址apk安裝后默認解壓后的dex路徑,目前dalvik并不支持使用PathClassLoader來加載未安裝的apk,但也有文章說art可以實現,暫未驗證,不能確認。DexClassLoader
繼承自BaseDexClassLoader,可以直接加載dex,壓縮文件(apk文件),jar文件,是實現android插件化一個重要的元素,可以幫我們完成對為安裝的插件apk的加載過程.
android基本加載知識記錄,已留備存。
Enjoytoday,EnjoyCoding