文章目录
一、ClassLoader.java#loadClass 类加载函数源码分析
二、BaseDexClassLoader.java#findClass 函数源码分析
一、ClassLoader.java#loadClass 类加载函数源码分析
分析类加载器的 双亲委派机制 ; 在 ClassLoader.java 类加载器中 , 双亲委托机制如下 :
首先 , 查看要加载的 Java 类是否已经被加载了 , 如果已经被加载 , 直接返回 ;
// 如果已经被加载了 , 则直接返回 Class<?> clazz = findLoadedClass(className);
如果没有被加载过 , 则开始进行双亲委派 , 让父节点类加载器加载该类 ;
// 如果还没有进行加载 , 则开始双亲委派 if (clazz == null) { try { // 让父节点类加载器加载该类 clazz = parent.loadClass(className, false); } catch (ClassNotFoundException e) { // Don't want to see this. }
如果父类没有加载成功 , 返回空 , 这是双亲委派轮完一轮之后 , 发现父节点都没有加载成功 , 则自己开始加载 , 如果自己加载不了 , 则继续委托给子节点执行加载 ;
// 这是双亲委派轮完一轮之后 , 发现父节点都没有加载成功 // 则自己开始加载 // 如果自己加载不了 , 则继续委托给子节点执行加载 if (clazz == null) { clazz = findClass(className); }
实际上加载类的方法是 findClass 函数 , 这是类加载过程的核心业务 ;
ClassLoader.java#loadClass 类加载函数源码 :
public abstract class ClassLoader { /** * 加载具有指定名称的类,可以选择在 * 装载。执行以下步骤: * <ol> * <li>调用{@link#findLoadedClass(String)}以确定请求的 * 类已加载</li> * <li>如果类尚未加载:在 * 父类加载器</li> * <li>如果类尚未加载:调用 * {@link#findClass(String)}查找类</li> * </ol> * <p> * <strong>注意:</strong>在Android参考实现中 * {@code resolve}参数被忽略;类从不链接。 * </p> * * @返回{@code Class}对象。 * @param className * 要查找的类的名称。 * @param-resolve * 指示加载后是否应解析该类。这 * 参数在Android参考实现中被忽略; * 未解析类。 * @ClassNotFoundException * 如果找不到该类。 */ protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { // 如果已经被加载了 , 则直接返回 Class<?> clazz = findLoadedClass(className); // 如果还没有进行加载 , 则开始双亲委派 if (clazz == null) { try { // 让父节点类加载器加载该类 clazz = parent.loadClass(className, false); } catch (ClassNotFoundException e) { // Don't want to see this. } // 这是双亲委派轮完一轮之后 , 发现父节点都没有加载成功 // 则自己开始加载 // 如果自己加载不了 , 则继续委托给子节点执行加载 if (clazz == null) { // ★ 核心跳转 clazz = findClass(className); } } return clazz; } }
源码路径 : /libcore/libdvm/src/main/java/java/lang/ClassLoader.java#loadClass
二、BaseDexClassLoader.java#findClass 函数源码分析
在类加载器中 , findClass 函数是核心业务 , 加固厂商在 Dalvik 虚拟机下 , 使用的类加载器是 DexClassLoader , 该类加载器只定义了构造函数 , findClass 函数定义在其父类 BaseDexClassLoader 中 ;
下面分析 BaseDexClassLoader 中的 findClass 方法 ;
在 BaseDexClassLoader 中的 findClass 函数中 , 主要调用了 DexPathList pathList 成员的 findClass 函数 ;
Class c = pathList.findClass(name, suppressedExceptions);
DexPathList pathList 成员在 BaseDexClassLoader 构造函数 , 即实例化时 ,
public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent) { super(parent); this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory); }
就已经构造完毕 , 其中包含了所有的字节码类信息 ,
BaseDexClassLoader.java#findClass 函数源码 :
/** * 用于各种基于dex的数据库之间的通用功能的基类 * {@link ClassLoader}实现。 */ public class BaseDexClassLoader extends ClassLoader { private final DexPathList pathList; /** * 构造一个实例。 * * @param dexPath 包含类和 * 资源,由{@code File.pathSeparator}分隔,其中 * Android上的默认值为{@code”:“} * @param optimizedDirectory 目录,其中包含优化的dex文件 * 应该是书面的;可能是{@code null} * @param libraryPath 包含本机 * 库,由{@code File.pathSeparator}分隔;可能是 * {@code null} * @param parent 父类加载器 */ public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent) { super(parent); this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory); } @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; } }