第十二章 理解 ClassLoader
热修复和插件化是目前比较热门的技术,要想更好地掌握它 需要先了 ClassLoader。
12.1 Java 中的 ClassLoader
12.1.1 ClassLoader 的类型
1. Bootstrap ClassLoader
C/C++ 编写的加载器,用于加载 JDK 的核心类,如:java.lang.
*,java.util.*
,它会加载以下目录中的类库:
$JAVA_HOME/jre/lib
目录- -Xbootclasspath 参数指定的目录
Java 虚拟机的启动就是通过 Bootstrap ClassLoader 创建-个初始类来完成的。
2. Extensions ClassLoader
Java 中实现类为 ExtClassLoader,用于加载 Java 的扩展类,主要是以下目录中的类库:
- 加载
$JAVA_HOME/jre/lib/ext
目录 - 系统数学 java.ext.dir 指定的目录
3. Application ClassLoader
Java 中实现类为 AppClassLoader,又可以称作 System ClassLoader,因为代码中可以通过 ClassLoader.getSystemClassLoader 方法获取。
会加载以下目录的类库:
- 当前程序的 Classpath 目录
- 系统属性 java.class.path 指定的目录
4. Custom ClassLoader
可以通过继承 java.lang.ClassLoader 类的方式实现自己的类加载器,之前的 ExtClassLoader 与 AppClassLoader 也是继承了该类。
12.1.2 ClassLoader 继承关系
- ClassLoader 是一个抽象类,其中定义了 ClassLoader 的主要功能。
- SecureClassLoader 继承了抽象类 ClassLoader,但本身无法加载类,只是扩展了 ClassLoader,加入了权限方面的功能。
- URLClassLoader 继承自 SecureClassLoader,主要是可以通过 URL 路径从 jar 文件和文件夹中加载类。
- ExtClassLoader 和 AppClassLoader 都继承自 URLClassLoader,他们都是 Launcher 的内部类。Launcher Java 虚拟机的人口应用, ExtClassLoader AppClassLoader 都是在 Launcher 中进行初始化的。
12.1.3 双亲委派
优势:
- 避免重复加载
- 更加安全
当然也有缺点,在 深入理解 Java 虚拟机中有更详细的说明。
12.1.4 自定义 ClassLoader
实现自定义 ClassLoader 需要如下步骤:
- 定义一个自定义的 ClassLoader 并继承(可间接继承)抽象类 ClassLoader。
- 复写 findClass 方法,并在其中调用 defineClass 方法。
12.2 Android 中的 ClassLoader
12.2.1 ClassLoader 的类型
1. BootClassLoader
与 Java 不同,Android 中的 BootClassLoader 是由 Java 实现的。BootClassLoader 是 ClassLoader 的内部类,并继承自 ClassLoader ,BootClassLoader 个单例类,需要注意的是 BootClassLoader 的访问修饰符是默认的,只有在同个包中才 可以访问,因此我们在应用程序中是无发直接调用的。
2. DexClassLoader
DexClassLoader 可以加载 dex 文件以及包含 dex 的压缩文件(apk 或 jar 文件)。
DexClassLoader 继承自 BaseDexClassLoader ,方法都在 BaseDexClassLoder 实现。
3. PathClassLoader
Android 系统使用 PathClassLoader 来加载系统类和应用程序的类。它继承自 BaseDexClassLoader,也都在 BaseDexClassLoader 中实现。
但构造方法中没有指定路径,实际上其内置了路径,一般为 /data/dalvik-cache
,这里存储着安装的 apk 的 dex 文件。
12.2.2 ClassLoader 的继承关系
- ClassLoader 是一个抽象类,定义了类加载器的主要功能。BootClassLoader 是其内部类。
- SecureClassLoader 类和 JDK 8 中的 SecureClassLoader 类的代码一致。
- URLClassLoader 类和 JDK 8 中的 URLClassLoader 类的代码一致。
- InMemoryDexClassLoader 是 Android 8.0 新增的类加载器,继承于 BaseDexClassLoader,用于加载内存中的 dex 文件。
- BaseDexClassLoader 继承自 ClassLoader,是 ClassLoader 的具体实现类。有三个子类。
12.2.3 ClassLoader 加载过程
其中 Element 为 DexPathList 的静态内部类,抽象出了一个类加载的实体。而 DexFile 用于加载某个 dex 文件。最终在 loadClassBinaryName 方法会调用 defineClass 方法,最终调用 defineClassNative 方法来加载文件,该方法为 native 方法。
12.2.4 BootClassLoader 的创建
BootClassLoader 是在 Zygote 进程的 Zygote 入口方法中被创建,用于加载 preloaded-classes 文件中存有的预加载类。
12.2.5 PathClassLoader 的创建
PathClassLoader 是在 SystemServer 进程中通过工厂模式创建的。
12.3 本章小结
- Java 的引导类加载器是由 C++ 编写的,Android 中的引导类则是用 Java 编写的。
- Android 的继承关系要比 Java 继承关系复杂,提供的功能更多。
- 由于 Android 中加载的不再是 Class 文件,因此 Android 中没有 ExtClassLoader 和 AppClassLoader,而是使用了 PathClassLoader 和 DexClassLoader