主要介紹幾個知識點:
參考資料
java中常用的classLoader
說到android中的classLoader,就不能不先說說java中的classLoader是什么。
所謂classLoader就是負(fù)責(zé)將編譯好的class文件加載到指定位置的實現(xiàn)類。具體來說,我們編寫java代碼時,需要將其編譯成.class文件,最終運行時就需要將這些class文件加載到內(nèi)存才能運行,而加載這些class文件的方法就可以成為classLoader。
在java中常用的classLoader有以下三種:
Bootstrap Classloder
這個類加載使用C++語言實現(xiàn),是虛擬機(jī)自身的一部分。他是三個類加載器中最頂層的加載類,主要負(fù)責(zé)加載%JAVA_HOME%/lib下的核心類或者jar加載到內(nèi)存中。(值得注意的是,Bootstrao Loader被設(shè)計成只能加載包名為java、javax、sun等開頭的類.)
Extention Classloder
擴(kuò)展類的加載器,由java語言實現(xiàn),主要負(fù)載加載%JAVA_HOME%/lib/ext目錄下的類庫,或者是系統(tǒng)指定的類庫。
AppClassloader
主要負(fù)責(zé)加載系統(tǒng)類路徑或者指定路徑下的類庫。
以上三種是java中定義的ClassLoader。
下面介紹android中常用的類加載器。
classLoader
所有的classLoader的基類,他是一個抽象類,所有的classLoader最終都會繼承自他,我們?nèi)绻枰远xclassLoader也需要直接或者間接的繼承他,并實現(xiàn)其中的findClass方法,并通過defineClass創(chuàng)建一個類實例。自定義類加載的示例如下:
class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the class data from the connection
//省略
}
}
BaseDexClassLoader
BaseDexClassLoader繼承自ClassLoader,只是對其進(jìn)行了進(jìn)一步的封裝,并沒有實現(xiàn),他有兩個直接的子類PathClassLoader和DexClassLoader。
簡單介紹一下他的構(gòu)造函數(shù):
public BaseDexClassLoader(String dexPath, File optimizedDirectory, String librarySearchPath, ClassLoader parent) {
//dexPath 代表目標(biāo)類所在的apk、DEX或者JAR文件的路徑
//optimizedDirectory用于指定解壓出來的dex文件存放的路徑
//librarySearchPath用于指定類中所使用的C/C++庫存放的路徑
//parent 用于指定該加載器的父加載器,一般為當(dāng)前執(zhí)行類的加載器
}
關(guān)于BaseDexClassLoader還有一點要補(bǔ)充的是,由于dex文件被包含在APK或者jar文件中,因此在加載目標(biāo)類之前需要先從APK或者jar文件中加壓處dex文件,optimizedDirectory即為指定解壓出來的dex文件存放的路徑,這也是對apk中dex根據(jù)平臺ODEX優(yōu)化的過程。
DexClassLoader
DexClassLoader用于加載包含dex的JAR或者APK文件,但是他不能加載jar或者apk文件。他最終加載的都是dex文件,雖然他是從.jar或者.zip,.apk等結(jié)尾的文件中加載,但是他們最終都會生成一個對應(yīng)的dex文件,他操作的還是dex文件。DexClassLoader繼承自BaseDexClassLoader,原理如下:
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
}
由代碼不能看出,DexClassLoader只是簡單的對BaseDexClassLoader進(jìn)行了一層封裝,并且指定了optimizedDirectory的路徑為一個新的文件路徑,DexClassLoader通過指定自己的optimizedDirectory,所以它可以加載外部的dex,因為這個dex會被復(fù)制到內(nèi)部路徑的optimizedDirectory。
所以,DexClassLoader一般用來作為動態(tài)加載的加載器。
PathClassLoader
PathClassLoader也是繼承自BaseDexClassLoader,他主要用于加載apk,一般應(yīng)用于加載android的系統(tǒng)類和app應(yīng)用的類。他的實現(xiàn)如下:
public 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);
}
}
可以看到,PathClassLoader將optimizedDirectory置為null,而optimizedDirectory是用來指定apk或者jar解壓出來的dex存放的位置,如果optimizedDirectory為null,則使用其默認(rèn)路徑/data/dalvik-cache,因此無法加載外部的apk的dex,只能加載內(nèi)部的dex,這些大都是存在系統(tǒng)中已經(jīng)安裝過的apk里面的。
URLClassLoader
URLClassLoader只能加載jar文件,但是dalvik虛擬機(jī)不能識別jar,所以在android中無法使用這個加載器。
InMemoryDexClassLoader
InMemoryDexClassLoader也是繼承自BeseDexClassLoader,是API26新增的加載器,用于加載內(nèi)存中的dex文件。
DelegateLastClassLoader
DelegateLastClassLoader繼承自PathClassLoader,是API27新增的加載器,用于指定最后的查找策略,查找順序如下:先判斷自己是否加載此類,然后在判斷此類的加載器是否加載過此類,最后委托給指定的父加載器。
classloader的雙親委托模型
classLoader雙親委托模型,當(dāng)要加載某個類時,先判斷自己是否有加載過此類,如果自己沒有加在過此類的話,進(jìn)而判斷父類是否加載過,如果某個父類加在過這個類的話,就直接返回,不重復(fù)加載。如果一直到頂級父類都沒有加載此類的話,這個加載任務(wù)就會分發(fā)下來,最后用當(dāng)前類加載器去加載該類。
類加載機(jī)制實現(xiàn)熱修復(fù)方案
通過使用dexClassloader動態(tài)修改加載dex的順序即可達(dá)到熱修復(fù)的目的。