ClassLoader類加載源碼解析
Java類加載器
1、BootClassLoader: 用于加載Android Framework層class文件。
2、PathClassLoader: 用于Android應(yīng)用程序類加載器??梢约虞d指定的dex,jar、zip、zpk中的classes.dex
3、DexClassLoader:加載指定的dex,以及jar、zip、apk中的classes.dex
源碼解析
1.ClassLoader中提供loadClass用于加載指定類
//ClassLoader.java public Class<?> loadClass(String name) throws ClassNotFoundException { //該處調(diào)用了兩個參數(shù)的重載方法 return loadClass(name, false); } protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { //先查一下該類是否已經(jīng)加載過了 Class<?> c = findLoadedClass(name); if (c == null) { try { //雙親委托機制,先讓爸爸去找 if (parent != null) { c = parent.loadClass(name, false); } else { //如果parent為null,則用BootClassLoader進行加載 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { //如果都找不到就自己去找,此方法在子類BaseDexClassLoader類中有重寫 c = findClass(name); } } return c; }
2.BaseDexClassLoader類中對findClass有重寫,也是實際會使用執(zhí)行的
//BaseDexClassLoader.java //查找class @Override protected Class<?> findClass(String name) throws ClassNotFoundException { ... //這里通過pathList變量來查找,而pathList是在BaseDexClassLoader的構(gòu)造方法中初始化的 Class c = pathList.findClass(name, suppressedExceptions); ... return c; } private final DexPathList pathList; public BaseDexClassLoader(String dexPath, File optimizedDirectory, String librarySearchPath, ClassLoader parent, boolean isTrusted) { super(parent); //構(gòu)造方法中初始化pathList變量 this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted); }
3.BaseDexClassLoader中是通過調(diào)用DexPathList中的findClass來實現(xiàn)的,那么接下來我們分析一下DexPathList是怎么實現(xiàn)的
//DexPathList.java //是一個Element數(shù)組,一個element中包含一個 DexFile,DexFile就代表一個Dex文件,里面的native(C/C++)函數(shù)來進行Dex的加載工作 private Element[] dexElements; public Class<?> findClass(String name, List<Throwable> suppressed) { for (Element element : dexElements) { //此處調(diào)用Element的findClass來實現(xiàn), Class<?> clazz = element.findClass(name, definingContext, suppressed); if (clazz != null) { return clazz; } } return null; } // Element為DexPathList的內(nèi)部類 static class Element { private final File path; //一個DexFile就代表一個Dex文件 private final DexFile dexFile; //有多個構(gòu)造方法,但都僅是將值傳過來,讓Element來持有一個DexFile public Element(DexFile dexFile) { this.dexFile = dexFile; this.path = null; } public Class<?> findClass(String name, ClassLoader definingContext, List<Throwable> suppressed) { //通過DexFile來加載類 return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed) : null; } } DexPathList(ClassLoader definingContext, String dexPath, String librarySearchPath, File optimizedDirectory, boolean isTrusted) { //通過makeDexElements方法為dexElements初始化 this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions, definingContext, isTrusted); } //騰訊系的熱修復(fù),諸如微信tinker、qq空間qfix原理便是反射此方法,將修復(fù)后的類打包成dex,通過反射該方法來將文件轉(zhuǎn)化為Element,并將新生成的element放到dexElements前面,這樣下次系統(tǒng)再去尋找某個class時,會先從修復(fù)后的dex中來找class,找到后便不再繼續(xù)查找,從而修復(fù)該class,此方式便為插樁 private static Element[] makeDexElements(List<File> files, File optimizedDirectory, List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) { Element[] elements = new Element[files.size()]; ... for (File file : files) { if (name.endsWith(DEX_SUFFIX)) { //以 .dex 結(jié)尾的 // Raw dex file (not inside a zip/jar). //加載dex文件 dex = loadDexFile(file, optimizedDirectory, loader, elements); if (dex != null) { elements[elementsPos++] = new Element(dex, null); } } } ... return elements; } private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader, Element[] elements) throws IOException { if (optimizedDirectory == null) { return new DexFile(file, loader, elements); } else { String optimizedPath = optimizedPathFor(file, optimizedDirectory); return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements); } }
4.這里通過 new DexFile 或者 loadDex方法來創(chuàng)建DexFile,兩者類似,那我們拿new DexFile 來舉例分析
//DexFile.java private DexFile(String sourceName, String outputName, int flags, ClassLoader loader, DexPathList.Element[] elements) throws IOException { ... //此處調(diào)用openDexFile來實現(xiàn) mCookie = openDexFile(sourceName, outputName, flags, loader, elements); ... } private static Object openDexFile(String sourceName, String outputName, int flags, ClassLoader loader, DexPathList.Element[] elements) throws IOException { //此處通過調(diào)用 openDexFileNative來實現(xiàn) return openDexFileNative(new File(sourceName).getAbsolutePath(), (outputName == null) ? null : new File(outputName).getAbsolutePath(), flags, loader, elements); } //openDexFileNative是一個native方法,是由C/C++來實現(xiàn)的 private static native Object openDexFileNative(String sourceName, String outputName, int flags, ClassLoader loader, DexPathList.Element[] elements);
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- jvm之java類加載機制和類加載器(ClassLoader)的用法
- Java類加載器ClassLoader用法解析
- Java運行時環(huán)境之ClassLoader類加載機制詳解
- 深入Spring Boot之ClassLoader的繼承關(guān)系和影響
- 關(guān)于Android中自定義ClassLoader耗時問題的追查
- 淺談Android Classloader動態(tài)加載分析
- Java Classloader機制用法代碼解析
- Java中ClassLoader類加載學(xué)習(xí)總結(jié)
- 詳解Android類加載ClassLoader
- 如何理解和運用ClassLoader
相關(guān)文章
Java類的繼承實例詳解(動力節(jié)點Java學(xué)院整理)
在Java開發(fā)中,我們常常用到繼承這一概念,可以說繼承是Java這類面向?qū)ο缶幊陶Z言的基石,今天小編一起和大家一起學(xué)習(xí)java類的繼承2017-04-04SpringBoot深入刨析數(shù)據(jù)層技術(shù)
這篇文章主要介紹了SpringBoot數(shù)據(jù)層技術(shù)的解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08java基于控制臺的學(xué)生學(xué)籍管理系統(tǒng)
這篇文章主要為大家詳細介紹了java基于控制臺的學(xué)生學(xué)籍管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-07-07SpringMVC中使用@PathVariable綁定路由中的數(shù)組的方法
這篇文章主要介紹了SpringMVC中使用@PathVariable綁定路由中的數(shù)組的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07使用Idea maven創(chuàng)建Spring項目過程圖解
這篇文章主要介紹了使用Idea maven創(chuàng)建Spring項目過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-02-02