ClassLoader类加载源码解析

作者:droidDing 时间:2023-11-25 18:17:09 

Java类加载器

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

ClassLoader类加载源码解析

ClassLoader类加载源码解析

源码解析

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


//ClassLoader.java
public 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<Throwable> 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<Throwable> 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<File> files, File optimizedDirectory,
  List<IOException> 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.java
private 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);

来源:https://blog.csdn.net/qq_23081779/article/details/91946548

标签:ClassLoader,类加载
0
投稿

猜你喜欢

  • Java中常见的陷阱题及答案

    2021-08-10 16:32:11
  • JavaMail实现带附件的邮件发送

    2021-10-21 15:00:09
  • 不使用Math.random方法生成随机数(随机数生成器)

    2021-11-28 05:08:46
  • WPF MVVM制作发送短信小按钮

    2021-10-26 09:48:12
  • SpringBoot详细讲解异步任务如何获取HttpServletRequest

    2023-01-04 18:01:09
  • 详解Java线程池队列中的延迟队列DelayQueue

    2023-08-30 01:22:04
  • springboot整合微信支付sdk过程解析

    2021-12-30 22:47:29
  • springboot搭建访客管理系统的实现示例

    2023-09-02 13:10:41
  • Java即将引入新对象类型来解决内存使用问题

    2023-03-30 18:12:42
  • Android 游戏开发之Canvas画布的介绍及方法

    2021-12-14 23:10:54
  • Android提高之MediaPlayer播放网络音频的实现方法

    2022-01-17 02:39:56
  • Android自定义控件(实现视图树绘制指示器)

    2023-11-14 17:11:59
  • java中sleep方法和wait方法的五个区别

    2023-08-27 18:37:23
  • 解决在for循环中remove list报错越界的问题

    2022-01-12 15:27:56
  • C#实现将聊天数据发送加密

    2022-09-10 05:56:35
  • SpringBoot通过自定义注解实现参数校验

    2023-09-21 21:11:02
  • SpringBoot+Netty+WebSocket实现消息发送的示例代码

    2023-08-16 00:02:52
  • Java实现inputstream流的复制代码实例

    2021-08-30 11:52:11
  • java 查找字符串所在的位置代码

    2023-12-22 21:48:17
  • 老生常谈ProgressBar、ProgessDialog的用法

    2022-05-02 16:08:58
  • asp之家 软件编程 m.aspxhome.com