DexClassLoader的创建和加载过程

1. 创建

(1)从new DexClassLoader(dexPath,optimizedDirectory,libraryPath,parentLoader)开始,调用父类BaseDexClassLoader构造器,用originalPath 保存了 dexPath,

pathList保存了一个由dexPath、optimizedDirectory、libraryPath、loader四个参数构建的DexPathList. 

dexClassLoader用来加载jar和apk. 其实还包括zip文件或者直接加载dex文件.它可以用来执行未安装的代码或者未被加载过的代码

4个参数

(1)dexPath: 需要被加载的文件地址,可以多个,用File.pathSeparator分割

(2)optimizedDirectory:dex文件被加载后会被编译器优化,优化之后的dex存放路径,不可以为null

这里着重看一下第二个参数,之前说过PathClassLoader中调用父类构造器的时候这个参数穿了null,因为加载app应用的时候我们的apk已经被安装到本地文件系统上了,其内部的dex已经被提取并且执行过优化了.

(3)libraryPath: 包含libraries的目录列表, plugin中有so文件, 需要将so拷贝到sd卡上, 然后把so所在的目录参数传入, 同样用File.pathSeparator分割

(4)parent:父类构造器

(2)DexPathList中的definingContext 保存了parentLoader,optimizedDirectory和libraryPath会被分割成数组,其中nativeLibraryDirectories保存了libraryPath被分割后的数组,并且加上了系统so库的目录,dexElements保存了由dexPath被分割后的对应的file而创建的Elememt

(3)dexElements它只是一个简单实体类,由一个File,一个ZipFile,一个DexFile组成,ZipFile是由jar、zip、apk形式的file包装成而来,DexFile使用native方法openDexFile打开了具体的file并输出到优化路径。


2. 加载class过程

使用类加载器的代码

try {

            File file =view.getActivity().getDir("dex",0);

            String optimizedDirectory =file.getAbsolutePath();

            DexClassLoader loader = newDexClassLoader("需要被加载的dex文件所在的路径",optimizedDirectory,null,context.getClassLoader());

            loader.loadClass("需要加载的类的完全限定名");

        } catch (ClassNotFoundException e) {

            e.printStackTrace();

        }

这样就完成了类的加载.

(1)DexClassLoader会调用findLoadedClass去虚拟机中查找当前class是不是已经被加载过了,如果加载过了, 就返回这个class, 如果没有被加载过, 那么返回null, 然后调用parent的loadClass. 直到最顶层根classloader的findLoadedClass方法,最顶层如果也没从虚拟机中确定此clss曾加载过, 那么最顶层开始真正加载class.
(2) BootClassLoader是ClassLoader的默认parentloader,所以它是加载器链中的顶端,也就是classloader的根节点,它没有parentloader, 它重写了loadClass来进行类的加载. 当然父加载器也是加载不到这个类, 返回null, 那么第二顶层的parentLoader开始加载, 发现也加载不到, 直到DexClassLoader里时, 发现能找到了, 那么直接加载并返回这个指定的class.
(3)findClass实现, 参照上面的创建流程图
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class clazz = pathList.findClass(name);
if (clazz == null) {
throw new ClassNotFoundException(name);
}
return clazz;
}
(4)pathList的findClass实现, 参照上面的创建流程图
public Class findClass(String name) {
for (Element element : dexElements) {
DexFile dex = element.dexFile; if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, definingContext); if (clazz != null) { return clazz;
}}}
return null;
}

(5) (1)(2)步骤请看此段逻辑 Loadclass的过程
try {
File file =view.getActivity().getDir("dex",0);
StringoptimizedDirectory = file.getAbsolutePath();
DexClassLoader loader =new DexClassLoader("需要被加载的dex文件所在的路径",optimizedDirectory,null,context.getClassLoader());
loader.loadClass("需要加载的类的完全限定名");
} catch(ClassNotFoundException e) {
e.printStackTrace();
}

protected Class<?>loadClass(String className, boolean resolve) throws ClassNotFoundException {
Class<?> clazz =findLoadedClass(className);

if (clazz == null) {
ClassNotFoundExceptionsuppressed = null;
try {
clazz =parent.loadClass(className, false);//自己验证没虚拟机中没有此类的时候, 让父类去虚拟机找找, 最顶层会都找不到, 会主动去加载.
} catch(ClassNotFoundException e) {
suppressed = e;
}

if (clazz == null) {//父类都加载不到的时候, 自己加载.
try {
clazz =findClass(className);
} catch(ClassNotFoundException e) {
e.addSuppressed(suppressed);
throw e;
}
}
}
return clazz;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值