深入理解 Java 虚拟机:双亲委派模型

深入理解 Java 虚拟机:双亲委派模型

  • 类加载器种类
    • 启动类加载器(Bootstrap ClassLoader)
    • 扩展类加载器(Extension ClassLoader)
    • 应用程序类加载器(Application ClassLoader)
    • 用户自定义类加载器(Customized Class Loader)
  • 双亲委派模型
    • 什么是双亲委派模型
    • 双亲委派模型工作原理
    • 双亲委派模型源码

类加载器种类

启动类加载器(Bootstrap ClassLoader)

使用 C++ 实现,是虚拟机的一部分。所有其他的类加载器,都是 Java 实现,独立于虚拟机外部,并且全程继承自抽象类 java.lang.ClassLoader

启动类加载器 负责把存放在 \lib 目录中,或者被 -Xbootclasspath 参数所指定的,并且是 虚拟机识别 的类库加载到虚拟机内存中。

扩展类加载器(Extension ClassLoader)

sun.misc.Launcher$ExtClassLoader 实现,负责加载 \lib\ext 目录中,或者被 java.ext.dirs 系统变量所指定的路径中的所有类库, 开发者可以直接获取此加载器。

应用程序类加载器(Application ClassLoader)

sun.misc.Launcher$AppClassLoader 实现,由于这个类加载器是 ClassLoader 中的 getSystemClassLoader() 方法的返回值,一般也称他为 系统类加载器

它负责加载 用户类路径上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序没有自定义过自己的类加载器,一般情况下就是 程序中默认的类加载器

用户自定义类加载器(Customized Class Loader)

用户可以自己定义类加载器来加载类。所有的类加载器都要继承 java.lang.ClassLoader 类并重写 findClass(String name) 方法。用户自定义类加载器 默认父加载器是应用程序加载器

双亲委派模型

什么是双亲委派模型

如下图这种层次关系,称为 双亲委派模型双亲委派模型 要求除了顶层的类加载器外,其余的类加载器 都应有自己的父类加载器。这里的类加载器之间的父子关系不会以继承的关系来实现,而都是以 组合关系来复用父加载器的代码

双亲委派模型工作原理

  1. 一个类加载器收到了类加载请求
  2. 自己先不尝试加载,而是委派给父类加载器去加载
  3. 由于每个类加载器都有父类,因此周而复始 直到传送到顶层的启动类加载器
  4. 如果父类加载器反馈无法加载,则子类尝试自己去加载
  5. 又是一个周而复始,从顶层向下一个个尝试,直到一个加载器成功加载

双亲委派模型源码

源码集中在 java.lang.ClassLoaderloadClass() 中。

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
{
	// 根据类的名称获取锁
    synchronized (getClassLoadingLock(name)) {
        // 首先,检查是否已经加载
        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 异常
                // 此时的 c == null,后续开始使用自己的加载器加载
            }

            if (c == null) {
                // c == null,意思就是被 catch 了,也就是父类加载器加载失败
                // 使用自身的加载器进行加载
                // 还失败,就会像上抛出 ClassNotFoundException
                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;
    }
}

你可能感兴趣的:(#,《深入理解,Java,虚拟机》,第二版,深入理解,Java,虚拟机,双亲委派模型,JVM,类加载器,类加载器执行过程)