一篇文章搞懂热修复类加载方案原理

ClassLoader 类型JAVA 中的 ClassLoader 可以加载 jar 文件和 Class文件(本质是加载 Class 文件),这一点在 Android 中并不适用,因为无论 DVM 还是 ART 它们加载的不再是 Class 文件,而是 dex 文件 。
Android 中的 ClassLoader 类型和 Java 中的 ClassLoader 类型类似,也分为两种类型,分别是 系统 ClassLoader 和 自定义 ClassLoader。其中 Android 系统 ClassLoader 包括三种分别是 BootClassLoader 、 PathClassLoader 和 DexClassLoader,而 Java 系统类加载器也包括3种,分别是 Bootstrap ClassLoader 、 Extensions ClassLoader 和 App ClassLoader。
BootClassLoaderAndroid 系统启动时会使用 BootClassLoader 来预加载常用类,与 Java 中的 BootClassLoader 不同,它并不是由 C/C++ 代码实现,而是由 Java 实现的,BootClassLoade 的代码如下所示
// libcore/ojluni/src/main/java/java/lang/ClassLoader.javaclass BootClassLoader extends ClassLoader {private static BootClassLoader instance;@FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED")public static synchronized BootClassLoader getInstance() {if (instance == null) {instance = new BootClassLoader();}return instance;}public BootClassLoader() {super(null);}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {return Class.classForName(name, false, null);}...}BootClassLoader 是 ClassLoader 的内部类,并继承自 ClassLoader。BootClassLoader 是一个单例类,需要注意的是 BootClassLoader 的访问修饰符是默认的,只有在同一个包中才可以访问,因此我们在应用程序中是无法直接调用的。
PathClassLoaderAndroid 系统使用 PathClassLoader 来加载系统类和应用程序的类,如果是加载非系统应用程序类,则会加载 data/app/$packagename 下的 dex 文件以及包含 dex 的 apk 文件或 jar 文件,不管是加载哪种文件,最终都是要加载 dex 文件,在这里为了方便理解,我们将 dex 文件以及包含 dex 的 apk 文件或 jar 文件统称为 dex 相关文件 。 PathClassLoader 不建议开发直接使用 。
// libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.javapublic class PathClassLoader extends BaseDexClassLoader {public PathClassLoader(String dexPath, ClassLoader parent) {super(dexPath, null, null, parent);}public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {super(dexPath, null, librarySearchPath, parent);}}PathClassLoader 继承自 BaseDexClassLoader,很明显 PathClassLoader 的方法实现都在 BaseDexClassLoader 中 。
PathClassLoader 的构造方法有三个参数:

  • dexPath:dex 文件以及包含 dex 的 apk 文件或 jar 文件的路径集合,多个路径用文件分隔符分隔,默认文件分隔符为‘:’ 。
  • librarySearchPath:包含 C/C++ 库的路径集合,多个路径用文件分隔符分隔分割,可以为 null
  • parent:ClassLoader 的 parent
DexClassLoaderDexClassLoader 可以加载 dex 文件以及包含 dex 的 apk 文件或 jar 文件,也支持从 SD 卡进行加载,这也就意味着 DexClassLoader 可以在应用未安装的情况下加载 dex 相关文件 。 因此,它是热修复和插件化技术的基础 。
public class DexClassLoader extends BaseDexClassLoader {public DexClassLoader(String dexPath, String optimizedDirectory,String librarySearchPath, ClassLoader parent) {super(dexPath, null, librarySearchPath, parent);}}DexClassLoader 构造方法的参数要比 PathClassLoader 多一个 optimizedDirectory 参数,参数 optimizedDirectory 代表什么呢?应用程序在第一次被加载的时候,为了提高以后的启动速度和执行效率,Android 系统会对 dex 相关文件做一定程度的优化,并生成一个 ODEX 文件,此后再运行这个应用程序的时候,只要加载优化过的 ODEX 文件就行了,省去了每次都要优化的时间,而参数 optimizedDirectory 就是代表存储 ODEX 文件的路径,这个路径必须是一个内部存储路径 。PathClassLoader 没有参数 optimizedDirectory,这是因为 PathClassLoader 已经默认了参数 optimizedDirectory 的路径为: /data/dalvik-cache。DexClassLoader 也继承自 BaseDexClassLoader,方法实现也都在 BaseDexClassLoader 中 。
关于以上 ClassLoader 在 Android 系统中的创建过程,这里牵扯到 Zygote 进程,非本文的重点,故不在此进行讨论 。
ClassLoader 继承关系
一篇文章搞懂热修复类加载方案原理

文章插图