内容简介:(1)作用:Android虚拟机运行的是Dex字节码(将Class文件合并优化生成的产物),ClassLoader用来加载dex文件。(2)分类
- ClassLoader是一个抽象类,其中定义了ClassLoader的主要功能。
- SecureClassLoader继承了抽象类ClassLoader,但SecureClassLoader并不是ClassLoader的实现类,而是拓展了ClassLoader类加入了权限方面的功能,加强了ClassLoader的安全性。
- URLClassLoader继承自SecureClassLoader,用来通过URl路径从jar文件和文件夹中加载类和资源。
- ExtClassLoader和AppClassLoader都继承自URLClassLoader,它们都是Launcher 的内部类,Launcher 是 Java 虚拟机的入口应用,ExtClassLoader和AppClassLoader都是在Launcher中进行初始化的。
二、Android中的ClassLoader
1、继承关系
- ClassLoader是一个抽象类,其中定义了ClassLoader的主要功能。BootClassLoader是它的内部类。
- SecureClassLoader继承了抽象类ClassLoader。SecureClassLoader并不是ClassLoader的实现类,而是拓展了ClassLoader类加入了权限方面的功能,加强了ClassLoader的安全性。
- URLClassLoader类继承自SecureClassLoader,用来通过URl路径从jar文件和文件夹中加载类和资源。
- InMemoryDexClassLoader是Android8.0新增的类加载器,继承自BaseDexClassLoader,用于加载内存中的dex文件。
- BaseDexClassLoader继承自ClassLoader,是抽象类ClassLoader的具体实现类,PathClassLoader和DexClassLoader都继承它。
2、作用和分类
(1)作用:
Android虚拟机运行的是Dex字节码(将Class文件合并优化生成的产物),ClassLoader用来加载dex文件。
(2)分类
分为系统类加载器和自定义类加载器。主要的系统类加载器:
- BootClassLoader
- PathClassLoader
- DexClassLoader
三、Android中ClassLoader源码分析
相关源码:
/dalvik/system1、ClassLoader
(1)构造函数:
protected ClassLoader() { this(checkCreateClassLoader(), getSystemClassLoader()); } protected ClassLoader(ClassLoader parent) { this(checkCreateClassLoader(), parent); } 复制代码
ClassLoader需要传入一个父ClassLoader,如果父ClassLoader不传的时候,通过 getSystemClassLoader方法,创建了一个PathClassLoader
public static ClassLoader getSystemClassLoader() { return SystemClassLoader.loader; } static private class SystemClassLoader { public static ClassLoader loader = ClassLoader.createSystemClassLoader(); } private static ClassLoader createSystemClassLoader() { String classPath = System.getProperty("java.class.path", "."); String librarySearchPath = System.getProperty("java.library.path", ""); return new PathClassLoader(classPath, librarySearchPath, BootClassLoader.getInstance()); } 复制代码
(2)loadClass方法:
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded //(1)先判断这个类是否被加载过 Class<?> c = findLoadedClass(name); if (c == null) { try { //(2)如果没被加载,先让父加载器进行加载 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 } //(3)如果父加载器加载失败,则自身进行加载 if (c == null) { // If still not found, then invoke findClass in order // to find the class. c = findClass(name); } } return c; } 复制代码
双亲委托机制:
(1)除了顶层的类加载器外,其他的类加载器都有自己的父类加载器,在加载类时首先判断这个类是否被加载过,如果已经加载则直接返回。
(2)如果未被加载过,则先尝试让父加载器进行加载,最终所有加载请求都会传递给顶层的加载器中。
(3)当父加载器发现未找到所需的类而无法完成加载请求时,子加载器的findClass方法中进行加载。
2、BaseDexClassLoader
(1)构造:
public BaseDexClassLoader(String dexPath, File optimizedDirectory, String librarySearchPath, ClassLoader parent) { this(dexPath, librarySearchPath, parent, null, false); } public BaseDexClassLoader(String dexPath, String librarySearchPath, ClassLoader parent, ClassLoader[] sharedLibraryLoaders, boolean isTrusted) { super(parent); this.sharedLibraryLoaders = sharedLibraryLoaders == null ? null : Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length); this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted); if (reporter != null) { reportClassLoaderChain(); } } 复制代码
- dexPath:指目标类所在的APK或jar文件的路径,如果要包含多个路径,路径之间必须使用特定的分割符分隔,特定的分割符可以使用System.getProperty(“path.separtor”)获得。
- optimizedDirectory:解压的dex文件存储路径,这个路径必须是一个内部存储路径,一般情况下使用当前应用程序的私有路径:/data/data//...。
- librarySearchPath:指目标类中所使用的C/C++库存放的路径
- parent:父加载器。
(2)DexPathList
DexPathList中维护着一个Element数组,这个数组中Element元素就是Dex文件
#DexPathList /*package*/ static class Element { @UnsupportedAppUsage private final File path; /** Whether {@code path.isDirectory()}, or {@code null} if {@code path == null}. */ private final Boolean pathIsDirectory; @UnsupportedAppUsage private final DexFile dexFile; private ClassPathURLStreamHandler urlHandler; private boolean initialized; @UnsupportedAppUsage public Element(DexFile dexFile, File dexZipPath) { if (dexFile == null && dexZipPath == null) { throw new NullPointerException("Either dexFile or path must be non-null"); } this.dexFile = dexFile; this.path = dexZipPath; // Do any I/O in the constructor so we don't have to do it elsewhere, eg. toString(). this.pathIsDirectory = (path == null) ? null : path.isDirectory(); } public Element(DexFile dexFile) { this(dexFile, null); } public Element(File path) { this(null, path); } ...... } 复制代码
3、BootClassLoader
Android平台上所有ClassLoader的最终parent。Android系统启动时会使用BootClassLoader来预加载常用类。
class BootClassLoader extends ClassLoader { private static BootClassLoader instance; @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") public static synchronized BootClassLoader getInstance() { if (instance == null) { instance = new BootClassLoader(); } return instance; } ... } 复制代码
BootClassLoader的访问修饰符是默认的,只有在同一个包中才可以访问
4、PathClassLoader
public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) { super(dexPath, null, librarySearchPath, parent); } @libcore.api.CorePlatformApi public PathClassLoader( String dexPath, String librarySearchPath, ClassLoader parent, ClassLoader[] sharedLibraryLoaders) { super(dexPath, librarySearchPath, parent, sharedLibraryLoaders); } 复制代码
- 使用PathClassLoader来加载系统类和应用程序的类,通常用来加载已安装的apk的dex文件
- 构造函数没有optimizedDirectory,无法定义dex文件路径,该参数默认值为/data/dalvik-cache
5、DexClassLoader
public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) { super(dexPath, null, librarySearchPath, parent); } 复制代码
DexClassLoader可以加载dex文件以及包含dex的压缩文件(apk和jar文件),在其父类BaseDexClassLoader里对".jar",".zip",".apk",".dex"后缀的文件最后都会生成一个对应的dex文件。
四、Android加载Class的过程
1、BaseDexClassLoader的findClass
@Override protected Class<?> findClass(String name) throws ClassNotFoundException { // First, check whether the class is present in our shared libraries. if (sharedLibraryLoaders != null) { for (ClassLoader loader : sharedLibraryLoaders) { try { return loader.loadClass(name); } catch (ClassNotFoundException ignored) { } } } // Check whether the class in question is present in the dexPath that // this classloader operates on. 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; } 复制代码
内部调用了DexPathList的findClass方法
#DexPathList private Element[] dexElements; ...... public Class<?> findClass(String name, List<Throwable> suppressed) { for (Element element : dexElements) { Class<?> clazz = element.findClass(name, definingContext, suppressed); if (clazz != null) { return clazz; } } if (dexElementsSuppressedExceptions != null) { suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); } return null; } public Class<?> findClass(String name, ClassLoader definingContext, List<Throwable> suppressed) { return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed) : null; } 复制代码
DexPathList内部包含了一个DexFile的数组dexElements。类加载的过程,就是遍历这个数组调用了DexFile的loadClassBinaryName方法,最终调用native方法defineClassNative。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。