千家信息网

ClassLoader类加载的示例分析

发表于:2025-01-23 作者:千家信息网编辑
千家信息网最后更新 2025年01月23日,这篇文章主要介绍了ClassLoader类加载的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Java类加载器1、BootCl
千家信息网最后更新 2025年01月23日ClassLoader类加载的示例分析

这篇文章主要介绍了ClassLoader类加载的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

Java类加载器

1、BootClassLoader: 用于加载Android Framework层class文件。
2、PathClassLoader: 用于Android应用程序类加载器。可以加载指定的dex,jar、zip、zpk中的classes.dex
3、DexClassLoader:加载指定的dex,以及jar、zip、apk中的classes.dex

源码解析

1.ClassLoader中提供loadClass用于加载指定类

//ClassLoader.javapublic Class loadClass(String name) throws ClassNotFoundException { //该处调用了两个参数的重载方法  return loadClass(name, false); }  protected Class loadClass(String name, boolean resolve)  throws ClassNotFoundException {  //先查一下该类是否已经加载过了   Class c = findLoadedClass(name);   if (c == null) {    try {     //双亲委托机制,先让爸爸去找     if (parent != null) {      c = parent.loadClass(name, false);     } else {      //如果parent为null,则用BootClassLoader进行加载      c = findBootstrapClassOrNull(name);     }    } catch (ClassNotFoundException e) {     // ClassNotFoundException thrown if class not found     // from the non-null parent class loader    }    if (c == null) {     //如果都找不到就自己去找,此方法在子类BaseDexClassLoader类中有重写     c = findClass(name);    }   }   return c; }

2.BaseDexClassLoader类中对findClass有重写,也是实际会使用执行的

//BaseDexClassLoader.java//查找class @Override protected Class findClass(String name) throws ClassNotFoundException {  ...  //这里通过pathList变量来查找,而pathList是在BaseDexClassLoader的构造方法中初始化的  Class c = pathList.findClass(name, suppressedExceptions);  ...  return c; } private final DexPathList pathList;public BaseDexClassLoader(String dexPath, File optimizedDirectory,   String librarySearchPath, ClassLoader parent, boolean isTrusted) {  super(parent);  //构造方法中初始化pathList变量  this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted); }

3.BaseDexClassLoader中是通过调用DexPathList中的findClass来实现的,那么接下来我们分析一下DexPathList是怎么实现的

//DexPathList.java//是一个Element数组,一个element中包含一个 DexFile,DexFile就代表一个Dex文件,里面的native(C/C++)函数来进行Dex的加载工作 private Element[] dexElements; public Class findClass(String name, List suppressed) {  for (Element element : dexElements) {   //此处调用Element的findClass来实现,   Class clazz = element.findClass(name, definingContext, suppressed);   if (clazz != null) {    return clazz;   }  }  return null; }// Element为DexPathList的内部类static class Element { private final File path;  //一个DexFile就代表一个Dex文件  private final DexFile dexFile;  //有多个构造方法,但都仅是将值传过来,让Element来持有一个DexFile  public Element(DexFile dexFile) { this.dexFile = dexFile;   this.path = null; }    public Class findClass(String name, ClassLoader definingContext,    List suppressed) {    //通过DexFile来加载类   return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)     : null;  } }DexPathList(ClassLoader definingContext, String dexPath,   String librarySearchPath, File optimizedDirectory, boolean isTrusted) {   //通过makeDexElements方法为dexElements初始化 this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,           suppressedExceptions, definingContext, isTrusted);}//腾讯系的热修复,诸如微信tinker、qq空间qfix原理便是反射此方法,将修复后的类打包成dex,通过反射该方法来将文件转化为Element,并将新生成的element放到dexElements前面,这样下次系统再去寻找某个class时,会先从修复后的dex中来找class,找到后便不再继续查找,从而修复该class,此方式便为插桩private static Element[] makeDexElements(List files, File optimizedDirectory,   List suppressedExceptions, ClassLoader loader, boolean isTrusted) {  Element[] elements = new Element[files.size()];  ...  for (File file : files) { if (name.endsWith(DEX_SUFFIX)) {    //以 .dex 结尾的     // Raw dex file (not inside a zip/jar).     //加载dex文件      dex = loadDexFile(file, optimizedDirectory, loader, elements);      if (dex != null) {       elements[elementsPos++] = new Element(dex, null);      }    } }   ...  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);  } }

4.这里通过 new DexFile 或者 loadDex方法来创建DexFile,两者类似,那我们拿new DexFile 来举例分析

//DexFile.javaprivate DexFile(String sourceName, String outputName, int flags, ClassLoader loader,   DexPathList.Element[] elements) throws IOException {  ...  //此处调用openDexFile来实现  mCookie = openDexFile(sourceName, outputName, flags, loader, elements);  ... }private static Object openDexFile(String sourceName, String outputName, int flags,   ClassLoader loader, DexPathList.Element[] elements) throws IOException {  //此处通过调用 openDexFileNative来实现  return openDexFileNative(new File(sourceName).getAbsolutePath(),         (outputName == null)          ? null          : new File(outputName).getAbsolutePath(),         flags,         loader,         elements); }//openDexFileNative是一个native方法,是由C/C++来实现的private static native Object openDexFileNative(String sourceName, String outputName, int flags,   ClassLoader loader, DexPathList.Element[] elements);

感谢你能够认真阅读完这篇文章,希望小编分享的"ClassLoader类加载的示例分析"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

0