Android中的ClassLoader
Java中的ClassLoader
可以加载jar
包和class
文件,在Android则不同。在Android中,不论DVM还是ART,加载的都是dex
文件。Android中的ClassLoader
可以分为系统类加载器和自定义加载器。
Android中ClassLoader
类继承关系如下
BootClassLoader
源码
BootClassLoader
是ClassLoader
的一个内部类,并继承自ClassLoader
。
它是包内可见的,因此我们没法使用它,也不能使用动态加载。
UrlClassLoader
UrlClassLoader
继承自SecureClassLoader
,它只能用于加载jar文件,但是由于 dalvik 不能直接识别jar,所以在 Android 中无法使用这个加载器。
BaseDexClassLoader
源码
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null);
if (reporter != null) {
reportClassLoaderChain();
}
}
public BaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexFiles);
}
|
BaseDexClassLoader
继承自ClassLoader
,用于加载各种dex
中的类。
具体参数的含义
dexPath
. 指目标类所在的APK或jar文件的路径,类装载器将从该路径中寻找指定的目标类,该类必须是APK或jar的全路径.如果要包含多个路径,路径之间必须使用特定的分割符分隔,特定的分割符可以使用System.getProperty(“path.separtor”)获得。最终做的是将dexPath路径上的文件ODEX优化到内部位置optimizedDirectory,然后,再进行加载的。
optimizedDirectory
. 由于dex文件被包含在APK或者Jar文件中,因此在装载目标类之前需要先从APK或Jar文件中解压出dex文件,该参数就是制定解压出的dex 文件存放的路径。这也是对apk中dex根据平台进行ODEX优化的过程。其实APK是一个程序压缩包,里面包含dex文件,ODEX优化就是把包里面的执行程序提取出来,就变成ODEX文件,因为你提取出来了,系统第一次启动的时候就不用去解压程序压缩包的程序,少了一个解压的过程。这样的话系统启动就加快了。为什么说是第一次呢?是因为DEX版本的也只有第一次会解压执行程序到 /data/dalvik-cache(针对PathClassLoader)或者optimizedDirectory(针对DexClassLoader)目录,之后也是直接读取目录下的的dex文件,所以第二次启动就和正常的差不多了。当然这只是简单的理解,实际生成的ODEX还有一定的优化作用。ClassLoader只能加载内部存储路径中的dex文件,所以这个路径必须为内部路径。
librarySearchPath
.指目标类中所使用的C/C++库存放的路径
parent
. 是指该装载器的父装载器,一般为当前执行类的装载器,例如在Android中以context.getClassLoader()作为父装载器。
PathClassLoader
源码
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
|
在PathClassLoader
的构造方法中没有参数optimizedDirectory
,这是因为PathClassLoader
已经默认了参数optimizedDirectory
的值为/data/dalvik-cache
目录。所以PathClassLoader
无法定义解压的dex文件的存储路径,因此PathClassLoader
通常用来加载已经安装的apk的dex文件。
DexClassLoader
源码
public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}
|
DexClassLoader
可以加载dex文件以及包含dex的压缩文件,不管加载哪种文件,最终都是要加载dex文件。
InMemoryDexClassLoader
源码
public InMemoryDexClassLoader(ByteBuffer[] dexBuffers, ClassLoader parent) {
super(dexBuffers, parent);
}
public InMemoryDexClassLoader(ByteBuffer dexBuffer, ClassLoader parent) {
this(new ByteBuffer[] { dexBuffer }, parent);
} |
InMemoryDexClassLoader
是API26的时候新增的。ByteBuffer数组构造了一个DexPathList,可用于内存中的dex文件。
ClassLoader 的双亲委托模型
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException{
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
return c;
}
private Class<?> findBootstrapClassOrNull(String name){
return null;
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
|
加载类的时候,首先判断有没有加载过,如果已经加载过了直接返回,否则就判断父加载器是否存在。如果存在父加载器,则调用父加载器的loadClass
方法,不存在则调用findBootstrapClassOrNull
方法。但是findBootstrapClassOrNull
会直接返回null
。所以最终又会调用到findClass
方法。而findClass
会直接抛出异常,所以这个需要子类来实现。这就是双亲委托模型。双亲委托模型一方面可以避免重复加载类,另一方面可以避免有人恶意编写一个类加载到JVM中。
Refer:https://www.jianshu.com/p/a620e368389a
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
评论(0)