认知 Java Class Loading

Class Loader

Class Loader

此前一次面试中,曾说起有关 ClassLoader 的话题。期间对方侃侃而谈,自己虽挖空心思,也不堪他的旁敲侧击,说不出个所以然来,只怪自己道行不够,丢人现眼,也遂下决心补上这块短板,恰逢近日稍有空暇,于是查资料,翻文档,希望就此实现这一愿望。

对 Java Class Loading 的认知,从OOP (Object Oriented Programming) 界的一句谚语开始,那就是:Everything is Object。以现实举例,张三是对象(object),李四也是对象(object),对这些个体加以抽象,形成了类(class)的概念。这类和对象的区别在于,前者是抽象的概念,不论是时间,还是空间均不存在这么一个东西;后者是具体的物件,可摸得着、看得见。

在 Java 中使用关键字 class 来定义一个类,经过编译之后,便会生成一个后缀为 .class 的文件。在 Java 程序运行时,JVM 需要载入这些 .class 文件到内存中,已构造成对应的 类(class)。而这载入的过程正是由 java.lang.ClassLoader 的实例来完成,根据 JVM 的策略,不同的类(class)被组织进不同的 jar 文件,进而按照重要级别划分成不同的等级,由不同的 class loader 来负责载入,如图所示。

假定 MyMainClass 是某个程序的主类,当执行 java MyMainClass 时,系统就会启动下一个新的 JVM。此时 bootstrap class loader 会立即载入核心的 Java 类(class),例如 在 rt.jar 中的 runtime 类(class) 和 i18n.jar 中的 internationalization 类(class)。

接下来,extension class loader 会接过接力棒,负责载入 extension library,具体的讲,就是由 ExtClassLoader 载入所有在 java.ext.dirs 路径(通常为 lib/ext)上的 jar 文件。

第三步,也是在开发人员看来最为关键的一步,application class loader 载入 java.class.path 路径(默认为当前路径,也可以通过 -classpath 或 -cp,或者设置CLASSPATH 进行修改)上的 jar 文件。

了解了上述流程之后,再来看Java Platform API Specification 对 java.lang.ClassLoader 类的描述,从中可以知道 ClassLoader 使用代理模型来搜索类和资源,并且每一个实例都会有一个与之关联的、“父”的 class loader。当 ClassLoader 实例被要求查找类或资源时,其就会让其父的 class loader 代为执行,如果执行无果,再由自己来执行。

以下代码是从 java.lang.ClassLoader 的片段,其中第8和11行是自行加入的注释,其余为官方源码,上述说法即由此得以印证。

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
protected synchronized Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException {
    // First, check if the class has already been loaded
    Class c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
                // delegate to its parent class loader
                c = parent.loadClass(name, false);
            } else {
                // no parent class loader, so delegate to bootstrap class loader
                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.
            c = findClass(name);
        }
    }
    if (resolve) {
        resolveClass(c);
    }
    return c;
}

以下为写作过程中所参考的文档资料:

  1. The basics of Java class loaders
  2. Internals of Java Class Loading
  3. Understanding Extension Class Loading
  4. 重温java之classloader体系结构(含hotswap)
  5. 深入JVM

Leave a comment

Your comment