文章目录
- 一、分析 PathClassLoader 源码
- 二、分析 BaseDexClassLoader 源码
- 三、分析 PathDexList 源码
- 四、 源码资源
一、分析 PathClassLoader 源码
PathClassLoader 是 Android 平台的类加载器 , 继承了 BaseDexClassLoader ;
代码语言:javascript复制public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
}
源码路径 : libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
二、分析 BaseDexClassLoader 源码
BaseDexClassLoader 中的 findClass 方法 , 就是查找字节码类的核心方法 ;
BaseDexClassLoader 的 protected Class<?> findClass(String name)
是 protected 属性的 , 不能直接调用 , 需要通过反射才能调用 ;
应用调用所有的类的入口 , 就是该函数 , 所有 Java 类都是通过该类进行查找的 ;
BaseDexClassLoader 中的 findClass 方法分析 : 传入查找的类名 name 后 , 会调用 DexPathList pathList 成员的额 findClass 方法 ;
代码语言:javascript复制public class BaseDexClassLoader extends ClassLoader {
/**
* Hook for customizing how dex files loads are reported.
*
* This enables the framework to monitor the use of dex files. The
* goal is to simplify the mechanism for optimizing foreign dex files and
* enable further optimizations of secondary dex files.
*
* The reporting happens only when new instances of BaseDexClassLoader
* are constructed and will be active only after this field is set with
* {@link BaseDexClassLoader#setReporter}.
*/
/* @NonNull */ private static volatile Reporter reporter = null;
private final DexPathList pathList;
public BaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) {
// TODO We should support giving this a library search path maybe.
super(parent);
this.pathList = new DexPathList(this, dexFiles);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException(
"Didn't find class "" name "" on path: " pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
}
源码路径 : libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
三、分析 PathDexList 源码
应用调用类 A.java 时 , 通过 PathClassLoader 调用 , PathClassLoader 没有实际内容 , 只是继承 BaseDexClassLoader , 主要靠 BaseDexClassLoader 的 findClass 方法查找 A.class 文件 , BaseDexClassLoader 又调用 DexPathList pathList 成员的 findClass 方法 , 查找 A.class 文件 ;
当应用运行时调用到某类 A.class 时 , 会通过 PathClassLoader 加载该类 , PathClassLoader 是一个包装类 , 其中封装了 PathDexList 类 , 该类中的 Element[] dexElements 成员存放着多个 Dex 文件 ;
每个 Dex 文件中封装了多个 Class 字节码文件 ; 查找某个具体的 A.class 时 , 主要是通过 DexPathList 的 findClass 方法 , 遍历 Element[] dexElements 成员 ,
Element[] dexElements 数组中保存的就是内存中的 DEX 文件 , 如果 APP 中有 3 个 DEX 文件 , 那么该数组就有 3 个元素 ;
然后逐个遍历 获取该 element 中的 dexFile , 这是 DexFile 类型文件 ,
调用 DexFile 的 loadClassBinaryName 加载对应的 A.class 类 , 如果找到了 A.class 类 , 直接返回 ; 如果没有找到 , 则继续遍历下一个 Element[] dexElements 元素 ;
代码语言:javascript复制/*package*/ final class DexPathList {
/**
* dex/resource (class path) 元素集合.
* 应该调用 pathElements , 但是 Facebook 应用通过反射修改 dexElements .
*/
private final Element[] dexElements;
public Class findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
DexFile dex = element.dexFile;
if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
// 注意 : 这里如果查找到想要的类 , 直接返回 , 不会去向后遍历
if (clazz != null) {
return clazz;
}
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
}
参考源码地址 : libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
四、 源码资源
源码资源 :
- GitHub 地址 : https://github.com/han1202012/HotFix
- CSDN 源码快照 : https://download.csdn.net/download/han1202012/16651312