ClassLoader是由JVM平台提供的类加载器。它允许程序从网络、硬盘甚至是内存加载Class,这就为Android插件化提供了最基础的技术保障。Android平台对字节码文件作了优化,摒弃了传统JVM需要的.jar文件,而是采用体积更小的.dex文件。因此,Android自定义了一系列ClassLoader以满足对dex加载。本文分为两部分,第一部分介绍Android的ClassLoader机制;第二部分介绍Android
ClassLoader机制在插件化中的应用。
Android的ClassLoader机制
类加载机制
为了表述方便,我们先来看一下《深入理解Java虚拟机》是对类加载机制怎么描述的:
Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校检、转换解析和初始化的,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
与那些在编译时进行链连接工作的语言不同,在Java语言里面,类型的加载、连接和初始化都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会为Java应用程序提供高度的灵活性,Java里天生可以同代拓展的语言特性就是依赖运行期动态加载和动态链接这个特点实现的。例如,如果编写一个面相接口的应用程序,可以等到运行时在制定实际的实现类;用户可以通过Java与定义的和自定义的类加载器,让一个本地的应用程序可以在运行时从网络或其他地方加载一个二进制流作为代码的一部分,这种组装应用程序的方式目前已经广泛应用于Java程序之中。从最基础的Applet,JSP到复杂的OSGi技术,都使用了Java语言运行期类加载的特性。
Java虚拟机类加载分为5个过程:加载、验证、准备、解析和初始化。
在加载阶段,虚拟机需要完成以下3件事情:
通过一个类的全限定名来获取定义此类的二进制字节流。
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
而加载阶段的第一步通过一个类的全限定名来获取定义此类的二进制字节流被放到了JVM外部去实现,这就给了我们决定如何去获取所需要类的权利。实现这个动作的代码模块我们称为ClassLoader。
双亲委派模型
无论是JVM还是Android,它们在加载类的时候都遵循双亲委派模型。双亲委派模型是这样的,每一个类加载器都有一个父加载器,如果某个类加载器收到了加载类的请求,它不会自己处理,而是交给父加载处理。每一层的类加载器都会这样向上传递,因此所有的类加载请求都会到达顶层的根加载器。只有父加载器不能处理加载请求时,子加载器才会尝试处理。具体代码如下:
public abstract class ClassLoader {
private ClassLoader parent;
protected ClassLoader(ClassLoader parentLoader) {
this.parent = parentLoader;
}
public Class<?> loadClass(String className) throws ClassNotFoundException {
return loadClass(className, false);
}
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
//查找类是否已经加载过
Class<?> clazz = findLoadedClass(className);
//类没有加载过
if (clazz == null) {
ClassNotFoundException suppressed = null;
try {
//交给父加载器处理
clazz = p