2.1.2-类加载和双亲委派模型

优质
小牛编辑
129浏览
2023-12-01

1.1 加载

将字节码数据从各种不同的数据源(class 文件、jar 文件等)中读到 JVM 中,映射为 Java 认可的数据结构(Class 对象)。

1.2 连接

  • 验证:过滤掉不合法的 class 文件。
  • 准备:为静态变量分配内存,此时不进行实例化,采用默认值。
  • 解析:

    1.3 初始化

    为静态变量赋予正确的初始值。

2. 类加载器类型

  • 启动类加载器
  • 扩展类加载器
  • 应用类加载器
  • 自定义类加载器

    3. 双亲委派模型

    3.1 原理

    该过程相当于递归,递归函数算法如下:

    (1)首先,检查目标类是否已在当前类加载器的命名空间中加载,是则返回 class  。
    (2)若类未被加载,检查是否有父类加载器,如果有,调用父类加载器。
    (3)如果没有,搜索类,如果找到则加载,如果找不到,调用自身的 findClass 方法。
    注:由于首先递归调用父类,再调用自身的 findClass 方法,所以执行 findClass 方法的是,从启动类到本类,第一能加载 class 的类加载器的方法。
    
    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) {
                      // 递归调用父类的 loadClass 方法。
                      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();
                  // 使用本地类进行加载,注意,此时这个本地是从启动类本类,第一能加载 class 的类加载器的方法。
                  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;
      }
    }
    

    3.2 双亲模型的作用

    任何一个类,都需要加载这个类的类加载器和这个类本身确定该类在虚拟机中的唯一性。那么为何不使用一个类加载器加载所有的类呢,底层类加载器分享由顶层类加载器加载的类。

    3.3 自定义类加载器的方法

    继承 ClassLoader 抽象类,重写 findClass() 方法。

    3.4 打破双亲模型的方法

    重写 loadClass 方法,在该方法中加载父类命名空间的类。

参考资料