通过 BaseDexClassLoader 构造方法可以知道,最重要的是去初始化 pathList 也就是 DexPathList 这个类,该类主要是用于管理 dex 相关文件
// libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {List<Throwable> suppressedExceptions = new ArrayList<Throwable>();Class c = pathList.findClass(name, suppressedExceptions); // 查找逻辑交给 DexPathListif (c == null) {ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class "" + name + "" on path: " + pathList);for (Throwable t : suppressedExceptions) {cnfe.addSuppressed(t);}throw cnfe;}return c;}BaseDexClassLoader 中最重要的是这个 findClass 方法,这个方法用来加载 dex 文件中对应的 class 文件 。而最终是交由 DexPathList 类来处理实现 findClass
DexPathList// libcore/dalvik/src/main/java/dalvik/system/DexPathList.javafinal class DexPathList {.../** class definition context */private final ClassLoader definingContext;/*** List of dex/resource (class path) elements.* Should be called pathElements, but the Facebook app uses reflection* to modify 'dexElements' (http://b/7726934).*/private Element[] dexElements;...DexPathList(ClassLoader definingContext, String dexPath,String librarySearchPath, File optimizedDirectory, boolean isTrusted) {...this.definingContext = definingContext;ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();// save dexPath for BaseDexClassLoaderthis.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,suppressedExceptions, definingContext, isTrusted);...}}查看 DexPathList 核心构造函数的代码可知,DexPathList 类通过 Element 来存储 dex 路径,并且通过 makeDexElements 函数来加载 dex 相关文件,并返回 Element 集合
// libcore/dalvik/src/main/java/dalvik/system/DexPathList.javaprivate static Element[] makeDexElements(List<File> files, File optimizedDirectory,List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {Element[] elements = new Element[files.size()];int elementsPos = 0;/** Open all files and load the (direct or contained) dex files up front.*/for (File file : files) {if (file.isDirectory()) {// We support directories for looking up resources. Looking up resources in// directories is useful for running libcore tests.elements[elementsPos++] = new Element(file);} else if (file.isFile()) {String name = file.getName();DexFile dex = null;if (name.endsWith(DEX_SUFFIX)) { // 判断是否是 dex 文件// Raw dex file (not inside a zip/jar).try {dex = loadDexFile(file, optimizedDirectory, loader, elements);if (dex != null) {elements[elementsPos++] = new Element(dex, null);}} catch (IOException suppressed) {System.logE("Unable to load dex file: " + file, suppressed);suppressedExceptions.add(suppressed);}} else { // 如果是 apk, jar, zip 等文件try {dex = loadDexFile(file, optimizedDirectory, loader, elements);} catch (IOException suppressed) {/** IOException might get thrown "legitimately" by the DexFile constructor if* the zip file turns out to be resource-only (that is, no classes.dex file* in it).* Let dex == null and hang on to the exception to add to the tea-leaves for* when findClass returns null.*/suppressedExceptions.add(suppressed);}// 将 dex 文件或压缩文件包装成 Element 对象,并添加到 Element 集合中if (dex == null) {elements[elementsPos++] = new Element(file);} else {elements[elementsPos++] = new Element(dex, file);}}if (dex != null && isTrusted) {dex.setTrusted();}} else {System.logW("ClassLoader referenced unknown path: " + file);}}if (elementsPos != elements.length) {elements = Arrays.copyOf(elements, elementsPos);}return elements;}总体来说,DexPathList 的构造函数是将 dex 相关文件(可能是 dex、apk、jar、zip , 这些类型在一开始时就定义好了)封装成一个 Element 对象,最后添加到 Element 集合中
其实,Android 的类加载器不管是 PathClassLoader,还是 DexClassLoader,它们最后只认 dex 文件,而 loadDexFile 是加载 dex 文件的核心方法,可以从 jar、apk、zip 中提取出 dex
// libcore/dalvik/src/main/java/dalvik/system/DexPathList.javapublic Class<?> findClass(String name, List<Throwable> suppressed) {for (Element element : dexElements) {Class<?> clazz = element.findClass(name, definingContext, suppressed);if (clazz != null) {return clazz;}}if (dexElementsSuppressedExceptions != null) {suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));}return null;}在 DexPathList 的构造函数中已经初始化了 dexElements,所以这个方法就很好理解了,只是对 Element 数组进行遍历,一旦找到类名与 name 相同的类时,就直接返回这个 class,找不到则返回 null
热修复实现通过上面的分析可以知道运行一个 Android 程序是使用到 PathClassLoader,即 BaseDexClassLoader ,而 apk 中的 dex 相关文件都会存储在 BaseDexClassLoader 的 pathList 对象的 dexElements 属性中 。
推荐阅读
- 使用Apache协议的是自由软件吗?
- 昆仑雪菊胎菊冲泡方式,昆仑雪菊茶的冲泡步骤
- 景洪勐宋古茶山,勐宋古茶山滑竹梁子
- 苦丁的功效与作用,发酵小叶苦丁茶的功效与作用
- Python实现数据压缩如此简单
- 禁忌喝的八种茶,喝苦瓜茶的禁忌
- 不要忽视 .gitignore
- 喝清茶能减肥吗,喝青茶能减肥吗
- 经期喝生姜茶可以么,经期喝什么茶
- 很少使用但很方便的HTML标签
