类加载器之源码解析

什么是类加载器

JVM 类加载过程分为三步

  1. 加载
  2. 链接
  3. 初始化

类加载器就是用来完成在加载阶段查找字节流的过程。

双亲委派机制

当一个类加载器收到加载请求时,会先将请求转发给「父」类加载器。在「父」类加载器没有找到所请求的类的情况下,该类加载器才会尝试去加载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}

if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);

// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}

ClassLoder

除了启动类加载器以外,其他所有类加载器都是ClassLoader的子类,其中两个重要的类加载器是扩展类加载器(extension class loader)和应用类加载器(application class loader),均由 Java 核心类库提供。

继承关系如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static class ExtClassLoader extends URLClassLoader {
}

static class AppClassLoader extends URLClassLoader {
}

public class URLClassLoader extends SecureClassLoader implements Closeable {
}

public class SecureClassLoader extends ClassLoader {
}

public abstract class ClassLoader {
}

ExtClassLoader 和 AppClassLoader

从上面的继承关系可以看到ExtClassLoaderAppClassLoader都继承自UrlClassLoader,但基于双亲委派机制中说的「父」类加载器并不是「父类」加载器,所以他们在接收到加载请求之后并不会发送到UrlClassLoader。

看下 ExtClassLoaderAppClassLoader 创建的过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public Launcher() {
Launcher.ExtClassLoader var1;
try {
// 创建 ExtClassLoader
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}

try {
// 创建 AppClassLoader,传入参数为 var1 为 ExtClassLoader 对象
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
...
}

AppClassLoader 的「父」类加载器就是 ExtClassLoader,而 ExtClassLoader 创建时传入参数是null,也就是对应的 BootstrapClassLoader

BootstrapClassLoader 是由C++编写,没有对应的 Java 对象,因此在 Java 中只能用 null 来指代。

  • 启动类加载器负责加载最为基础,最为重要的类,比如存放在 JRE 的 lib 目录下的 jar 包中的类,以及由虚拟机参数 -Xbootclasspath 指定的类。

  • ExtClassLoader 负责加载相对次要、但又通用的类,比如存放在 JRE 的 lib/ext 目录下的 jar 包中的类,以及由系统变量 java.ext.dirs 指定的类。

  • AppClassLoader 负责加载应用程序路径下的类。