Android开发经验谈Android开发Android进阶之路

Android动态加载系列 —— ClassLoader加载原理

2019-04-07  本文已影响0人  Ex_Joe

前言

什么是ClassLoader

Android中的类体现

  1. BootClassLoader: Dalvik/ART虚拟机用于加载Android系统类的Loader,应用层通过获取父ClassLoader的最终项。
  2. PathClassLoader: 我们知道,打包APK后实际上是把java文件都生成dex文件,而这个Loader就是在应用启动时,加载已安装APK的dex文件。
  3. DexClassLoader: 常见的动态加载机制都用这个类,传入指定路径加载指定dex文件。

加载原理

类加载源码解析

  1. BootClassLoader用于加载系统层的类,比较特殊,loadClass查询虚拟机中没有缓存时最终会调用到findClass ——> Native 方法 Class.classForName:


    BootClassLoader-findClass.png
  2. 其余的loadClass都是调用到下图中,先查找当前loader是否有加载到该类的缓存,若没有,就获取父加载器查找,递归直到父加载器不存在。
    因此总体来看这是一个先向上委托父加载器,再向下查找的过程。若查询为null,将从当前加载器加载类,最终会调用loadClass方法,加载成功就跳出递归。

ClassLoader-loadClass.png
  1. DexClassLoader和PathClassLoader 都是继承于BaseDexClassLoader,从构造方法可知,optimizedDirectory这个参数已经无效了,因为已经没有向下传递的,我们一起直接看看它的findClass方法。


    BaseDexClassLoader.png
BaseDexClassLoader-findclass.png
  1. 实际上调用的是DexPathList.findClass方法,这里有个dexElements,看看他是如何构造出来的。


    DexPathList-findClass.png
  2. 根据我们创建ClassLoader时,传入的dexPath,支持APK、DEX、JAR文件全路径,以/分隔符分开。分别调用loadDexFile,这就是我们生成最终可用的dex文件的过程。最终构造出dexElements。


    DexPathList-makePathElements.png
DexFile-loadDexFile.png
  1. 最终调用loadClassBinaryName,这个方法最终会调到底层Native 方法DextFile.defineClassNative。


    DexFile-loadClassBinaryName.png
DexFile-defineClassNative.png

使用方式

参数名 描述
dexPath 待提取dex的文件全路径,多个时以 ":" 分隔符(在Android中以File.pathSeparator定义)隔开
optimizedDirectory 提取到dex文件后存放文件夹路径,但现在已经无效了
libraryPath so文件所在文件夹路径, 多个时以 ":" 分隔符(在Android中以File.pathSeparator定义)隔开
parent 父classloader

举个例子吧

checkTextUtils.png

答案显而易见是不可以的,前面我们学到,类加载委托是从下至上,类查找是从上至下的,顶级类加载器父类BootClassloader查找到TextUtils时,会首先把类加载入缓存。级别更低的ClassLoader均从缓存获取成功,因此项目中使用PathClassloader才能加载到的TextUtils是无法成功的。


checkTextUtils-result.png Dextest.png loadExternDex.png loadExternDex-result.png

总结

native底层代码阅读:

上一篇下一篇

猜你喜欢

热点阅读