title: “Android解析ClassLoader(一)Java中的ClassLoader”
date: 2017-09-25 00:16
tag:
- Android应用层
- ClassLoader
categories: - Android应用层
本文首发于微信公众号「刘望舒」
关联系列
Java虚拟机系列
Android解析ClassLoader系列
前言
热修复和插件化是目前比较热门的技术,要想更好的掌握它们需要了解ClassLoader,因此也就有了本系列的产生,这一篇我们先来学习Java中的ClassLoader。
1.ClassLoader的类型
在Java虚拟机(一)结构原理与运行时数据区域这篇文章中,我提到过类加载子系统,它的主要作用就是通过多种类加载器(ClassLoader)来查找和加载Class文件到 Java 虚拟机中。
Java中的类加载器主要有两种类型,系统类加载和自定义类加载器。其中系统类加载器包括3种,分别是Bootstrap ClassLoader、 Extensions ClassLoader和 App ClassLoader。
1.1 Bootstrap ClassLoader
用C/C++代码实现的加载器,用于加载Java虚拟机运行时所需要的系统类,如java.lang.*、java.uti.*
等这些系统类,它们默认在$JAVA_HOME/jre/lib目录中,也可以通过启动Java虚拟机时指定-Xbootclasspath选项,来改变Bootstrap ClassLoader的加载目录。
Java虚拟机的启动就是通过 Bootstrap ClassLoader创建一个初始类来完成的。由于Bootstrap ClassLoader是使用C/C++语言实现的, 所以该加载器不能被Java代码访问到。需要注意的是Bootstrap ClassLoader并不继承java.lang.ClassLoader。
我们可以通过如下代码来得出Bootstrap ClassLoader所加载的目录:
public class ClassLoaderTest {
public static void main(String[]args) {
System.out.println(System.getProperty("sun.boot.class.path"));
}
}
打印结果为:
C:\Program Files\Java\jdk1.8.0_102\jre\lib\resources.jar;
C:\Program Files\Java\jdk1.8.0_102\jre\lib\rt.jar;
C:\Program Files\Java\jdk1.8.0_102\jre\lib\sunrsasign.jar;
C:\Program Files\Java\jdk1.8.0_102\jre\lib\jsse.jar;
C:\Program Files\Java\jdk1.8.0_102\jre\lib\jce.jar;
C:\Program Files\Java\jdk1.8.0_102\jre\lib\charsets.jar;
C:\Program Files\Java\jdk1.8.0_102\jre\lib\jfr.jar;
C:\Program Files\Java\jdk1.8.0_102\jre\classes
可以发现几乎都是$JAVA_HOME/jre/lib目录中的jar包,包括rt.jar、resources.jar和charsets.jar等等。
1.2 Extensions ClassLoader
用于加载 Java 的拓展类 ,拓展类的jar包一般会放在$JAVA_HOME/jre/lib/ext目录下,用来提供除了系统类之外的额外功能。也可以通过-Djava.ext.dirs选项添加和修改Extensions ClassLoader加载的路径。
通过以下代码可以得到Extensions ClassLoader加载目录:
System.out.println(System.getProperty("java.ext.dirs"));
打印结果为:
C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext;
C:\Windows\Sun\Java\lib\ext
1.3 App ClassLoader
负责加载当前应用程序Classpath目录下的所有jar和Class文件。也可以加载通过-Djava.class.path选项所指定的目录下的jar和Class文件。
1.4 Custom ClassLoader
除了系统提供的类加载器,还可以自定义类加载器,自定义类加载器通过继承java.lang.ClassLoader类的方式来实现自己的类加载器,除了 Bootstrap ClassLoader,Extensions ClassLoader和App ClassLoader也继承了java.lang.ClassLoader类。关于自定义类加载器后面会进行介绍。
2.ClassLoader的继承关系
运行一个Java程序需要用到几种类型的类加载器呢?如下所示。
public class ClassLoaderTest {
public static void main(String[] args) {
ClassLoader loader = ClassLoaderTest.class.getClassLoader();
while (loader != null) {
System.out.println(loader);//1
loader = loader.getParent();
}
}
}
首先我们得到当前类ClassLoaderTest的类加载器,并在注释1处打印出来,接着打印出当前类的类加载器的父加载器,直到没有父加载器终止循环。打印结果如下所示。
sun.misc.Launcher$AppClassLoader@75b84c92
sun.misc.Launcher$ExtClassLoader@1b6d3586
第1行说明加载ClassLoaderTest的类加载器是AppClassLoader,第2行说明AppClassLoader的父加载器为ExtClassLoader。至于为何没有打印出ExtClassLoader的父加载器Bootstrap ClassLoader,这是因为Bootstrap ClassLoader是由C/C++编写的,并不是一个Java类,因此我们无法在Java代码中获取它的引用。
我们知道系统所提供的类加载器有3种类型,但是系统提供的ClassLoader相关类却不只3个。另外,AppClassLoader的父类加载器为ExtClassLoader,并不代表AppClassLoader继承自ExtClassLoader,ClassLoader的继承关系如下所示。
可以看到上图中共有5个ClassLoader相关类,下面简单对它们进行介绍: