美文网首页
ClassLoader&双亲委派模型

ClassLoader&双亲委派模型

作者: leap_ | 来源:发表于2020-04-29 17:22 被阅读0次

类加载器的作用:

  • 类加载,通过类的权限定名获取此类的二进制字节流
  • 确定被加载的类在jvm中的唯一性

两个类是否相等的依据:是否由同一个ClassLoader加载

两个类是否相等的判断:

  • equals
  • isAssignableFrom
  • isInstance
类加载器的类型:
  1. 启动类加载器(Bootstrap ClassLoader)
  • 用于加载存放在<JAVA_HOME>\lib目录下和被-Xbootclasspath参数指定的类(事先定义好的类)
  • 仅按文件名识别,如:rt.jar,名字不符合的类库即使放在lib目录中也不会被加载
  • 无法被java程序直接使用
  1. 扩展类加载器(Extension ClassLoader)
  • 加载JAVA_HOME>\lib\ext目录中和被java.ext.dirs系统变量所指定的路径中的类
  • 开发者可以直接使用扩展类加载器
  1. 应用程序类加载器
  • 负责加载 用户类路径(ClassPath)上所指定的类库
  • 该类加载器是ClassLoader中的getSystemClassLoader()方法的返回值

双亲委派模型

双亲委派模型

注意点:

  • 除了顶层的启动类加载器,所有的加载器都有父类加载器
  • 加载器之前的关系是组合关系来复用父类加载器的代码,不是继承
双亲委派模型的工作流程代码实现在java.lang.ClassLoader的loadClass()
protected Class<?> loadClass(String name, boolean resolve) 
        throws ClassNotFoundException { 
    Class<?> c = findLoadedClass(name); 

  // 检查需要加载的类是否已经被加载过
    if (c == null) { 
        try { 
             // 若没有加载,则调用父加载器的loadClass()方法
            if (parent != null) { 
                c = parent.loadClass(name, false); 
            }else{ 
                // 若父类加载器为空,则默认使用启动类加载器作为父加载器
                c=findBootstrapClassOrNull(name); 
            } 
        } catch (ClassNotFoundException e) { 
            // 若父类加载器加载失败会抛出ClassNotFoundException, 
            //说明父类加载器无法完成加载请求 
        } 
        if(c==null){ 
            // 在父类加载器无法加载时 
            // 再调用本身的findClass方法进行类加载 
            c=findClass(name); 
        } 
    } 
    if(resolve){ 
        resolveClass(c); 
    } 
    return c; 
}
加载流程:
  1. 当一个加载器收到加载请求需求时,会提交给他的父类加载器去完成
  2. 只有当父类加载器反馈无法加载时,自己才会去加载
优点:

类加载器的层级关系保证了java类的带优先级的层次关系:

  • Object类只有启动类加载器会加载,所以只会有一个Object类,如果没有双亲委派模型,多个类加载加载Object类会出现多个Object类,无法保证java的最基础行为;

安卓的类加载器

  • BootClassLoader:加载framework中的类,如Activity.class
  • PathClassLoader:加载项目中的类,如MainActivity.class,其父加载器是BootClassLoader
  • DexClassLoader:加载指定目录的类,其父加载器也是BootClassLoader
  • InMemoryClassLoader:加载内存中的类,不如字节数组(类似动态代理中的那个东西)

类加载器加载类的原理:

BaseDexClassLoader:
  private final DexPathList pathList;

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
...
        Class c = pathList.findClass(name, suppressedExceptions);
...
    }
DexPathList:
    private Element[] dexElements;

    public Class<?> findClass(String name, List<Throwable> suppressed) {
        for (Element element : dexElements) {
            Class<?> clazz = element.findClass(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
        return null;
    }

    private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
            List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {
      Element[] elements = new Element[files.size()];
      int elementsPos = 0;
      /*
       * Open all files and load the (direct or contained) dex files up front.
       */
      for (File file : files) {
          if (file.isDirectory()) {
              // We support directories for looking up resources. Looking up resources in
              // directories is useful for running libcore tests.
              elements[elementsPos++] = new Element(file);
          } else if (file.isFile()) {
              String name = file.getName();

              DexFile dex = null;
              if (name.endsWith(DEX_SUFFIX)) {
                  // Raw dex file (not inside a zip/jar).
                  try {
                      dex = loadDexFile(file, optimizedDirectory, loader, elements);
                      if (dex != null) {
                          elements[elementsPos++] = new Element(dex, null);
                      }
                  } catch (IOException suppressed) {
                      System.logE("Unable to load dex file: " + file, suppressed);
                      suppressedExceptions.add(suppressed);
                  }
              } else {
                  try {
                      dex = loadDexFile(file, optimizedDirectory, loader, elements);
                  } catch (IOException suppressed) {
                      /*
                       * IOException might get thrown "legitimately" by the DexFile constructor if
                       * the zip file turns out to be resource-only (that is, no classes.dex file
                       * in it).
                       * Let dex == null and hang on to the exception to add to the tea-leaves for
                       * when findClass returns null.
                       */
                      suppressedExceptions.add(suppressed);
                  }

                  if (dex == null) {
                      elements[elementsPos++] = new Element(file);
                  } else {
                      elements[elementsPos++] = new Element(dex, file);
                  }
              }
              if (dex != null && isTrusted) {
                dex.setTrusted();
              }
          } else {
              System.logW("ClassLoader referenced unknown path: " + file);
          }
      }
      if (elementsPos != elements.length) {
          elements = Arrays.copyOf(elements, elementsPos);
      }
      return elements;
    }

    private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader,
                                       Element[] elements)
            throws IOException {
        if (optimizedDirectory == null) {
            return new DexFile(file, loader, elements);
        } else {
            String optimizedPath = optimizedPathFor(file, optimizedDirectory);
            return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements);
        }
    }

Element: DexPathList的一个静态内部类
       private final DexFile dexFile;

        public Class<?> findClass(String name, ClassLoader definingContext,
                List<Throwable> suppressed) {
            return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
                    : null;
        }

dexFile.loadClassBinaryName()是一个native方法


https://blog.csdn.net/qq_22393017/article/details/81811101

相关文章

  • ClassLoader&双亲委派模型

    类加载器的作用: 类加载,通过类的权限定名获取此类的二进制字节流 确定被加载的类在jvm中的唯一性 两个类是否相等...

  • Tomcat类载入器

    大家都知道,Java的类加载机制是双亲委派模型,那么什么是双亲委派模型呢?我们这里简要的说一下,双亲委派模型...

  • java类加载破坏双亲委派模型

    前面java类加载器与双亲委派模型中提到Java采用个双亲委派的方式来完成类加载,但是双亲委派模型并不是一个强制的...

  • Java 类加载

    双亲委派模型 并非强制 而是推荐 SPI 父类加载器需要子类加载器加载类 打破双亲委派模型 https://www...

  • sandBox源码分析之ClassLoader

    提起classLoader,就不由自主想起了java classLoader的双亲委派模型,那么到底什么是双亲委派...

  • 双亲委派模型

    一、类加载器简介:JVM启动时,会形成由三个类加载器组成的初始类加载器层次结构: Bootstrap ClassL...

  • 双亲委派模型

    一、为什么要用这种模型 保证相同的字节码文件不被重复加载 二、利用双亲委派模型加载类的过程 java.lang.C...

  • 双亲委派模型

    jdk1.2后 虚拟机 的类加载器 使用的就是双亲委派模型; 主要有三种加载器: 1:Bootstrap clas...

  • 双亲委派模型

    类与类加载器 类加载器非常重要,因为每个类加载器都有一个独立的类名称空间。比如我们要加载两个类,如果要比较两个类是...

  • 双亲委派模型

    为何需要双亲委派模型: 如果你自己重写一个String类, 会发生什么?两个字:安全 JVM运行流程, JVM基本...

网友评论

      本文标题:ClassLoader&双亲委派模型

      本文链接:https://www.haomeiwen.com/subject/qihnwhtx.html