基本知识

Java的类加载设计了一套双亲代理的模式,使得用户没法替换系统的核心类,从而让应用更安全。所谓双亲代理就是指,当加载类的时候首先去Bootstrap中加载类,如果没有则去Extension中加载,如果再没有才去AppClassLoader中去加载。从而实现安全和稳定。
Java ClassLoader
BootstrapClassLoader
引导类加载器 ,用来加载Java的核心库。通过底层代码来实现的,基本上只要parent为null,那就表示引导类加载器。
比如:charsets.jar、deploy.jar、javaws.jar、jce.jar、jfr.jar、jfxswt.jar、jsse.jar、management-agent.jar、plugin.jar、resources.jar、rt.jar
ExtClassLoader
拓展类加载器 ,用来加载Java的拓展的类库, ${JAVA_HOME}/jre/lib/ext/ 目录中的所有jar。
比如:cldrdata.jar、dnsns.jar、jfxrt.jar、localedata.jar、nashorn.jar、sunec.jar、sunjce_provider.jar、sunpkcs11.jar、zipfs.jar等等
AppClassLoader
系统类加载器 (不要被名字给迷惑),用来加载Java应用中的类。一般来说自己写的类都是通过这个加载的。而Java中 ClassLoader.getSystemClassLoader() 返回的就是AppClassLoader。(Android中修改了ClassLoader的逻辑,返回的会是一个PathClassLoader)
自定义ClassLoader
用户如果想自定义ClassLoader的话,只需要继承自 java.lang.ClassLoader 即可。
ClassLoader中与加载类相关的方法:
也许你不太了解上面几个函数的区别,没关系,我们来看下源码是如何实现的。
//ClassLoader.java
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) {
long t0 = System.nanoTime();
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.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
}
}
return c;
}
所以优先级大概如下:
loadClass → findLoadedClass → parent.loadClass/findBootstrapClassOrNull → findClass → defineClass
Android ClassLoader
在Android中ClassLoader主要有两个直接子类,叫做 BaseDexClassLoader 和 SecureClassLoader 。而前者有两个直接子类是 PathClassLoader 和 DexClassLoader (Android O添加了 InMemoryDexClassLoader ,略)。
我们只讨论PathClassLoader和DexClassLoader
PathClassLoader
用来加载安装了的应用中的dex文件。它也是Android里面的一个最核心的ClassLoader了。相当于Java中的那个AppClassLoader。
public class PathClassLoader extends BaseDexClassLoader {
/**
* Creates a {@code PathClassLoader} that operates on a given list of files
* and directories. This method is equivalent to calling
* {@link #PathClassLoader(String, String, ClassLoader)} with a
* {@code null} value for the second argument (see description there).
*
* @param dexPath the list of jar/apk files containing classes and
* resources, delimited by {@code File.pathSeparator}, which
* defaults to {@code ":"} on Android
* @param parent the parent class loader
*/
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
/**
* Creates a {@code PathClassLoader} that operates on two given
* lists of files and directories. The entries of the first list
* should be one of the following:
*
* <ul>
* <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as
* well as arbitrary resources.
* <li>Raw ".dex" files (not inside a zip file).
* </ul>
*
* The entries of the second list should be directories containing
* native library files.
*
* @param dexPath the list of jar/apk files containing classes and
* resources, delimited by {@code File.pathSeparator}, which
* defaults to {@code ":"} on Android
* @param librarySearchPath the list of directories containing native
* libraries, delimited by {@code File.pathSeparator}; may be
* {@code null}
* @param parent the parent class loader
*/
public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
}
它的实例化是通过调用 ApplicationLoaders.getClassLoader 来实现的。
它是在ActivityThread启动时发送一个BIND_APPLICATION消息后在handleBindApplication中创建ContextImpl时调用LoadedApk里面的 getResources(ActivityThread mainThread) 最后回到ActivityThread中又调用LoadedApk的 getClassLoader 生成的,具体的在LoadedApk的 createOrUpdateClassLoaderLocked 。
那么问题来了,当Android加载class的时候,LoadedApk中的ClassLoader是怎么被调用到的呢?
其实Class里面,如果你不给ClassLoader的话,它默认会去拿Java虚拟机栈里面的 CallingClassLoader ,而这个就是LoadedApk里面的同一个ClassLoader。
//Class.java
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName(className, true, VMStack.getCallingClassLoader());
}
查看VMStack的源码发现 getCallingClassLoader 其实是一个native函数,Android通过底层实现了这个。
//dalvik.system.VMStack
/**
* Returns the defining class loader of the caller's caller.
*
* @return the requested class loader, or {@code null} if this is the
* bootstrap class loader.
*/
@FastNative
native public static ClassLoader getCallingClassLoader();
底层想必最终也是拿到LoadedApk里面的ClassLoader。
DexClassLoader
它是一个可以用来加载包含dex文件的jar或者apk文件的,但是它可以用来加载非安装的apk。比如加载sdcard上面的,或者NetWork的。
public class DexClassLoader extends BaseDexClassLoader {
/**
* Creates a {@code DexClassLoader} that finds interpreted and native
* code. Interpreted classes are found in a set of DEX files contained
* in Jar or APK files.
*
* <p>The path lists are separated using the character specified by the
* {@code path.separator} system property, which defaults to {@code :}.
*
* @param dexPath the list of jar/apk files containing classes and
* resources, delimited by {@code File.pathSeparator}, which
* defaults to {@code ":"} on Android
* @param optimizedDirectory directory where optimized dex files
* should be written; must not be {@code null}
* @param librarySearchPath the list of directories containing native
* libraries, delimited by {@code File.pathSeparator}; may be
* {@code null}
* @param parent the parent class loader
*/
public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}
}
比如现在很流行的插件化/热补丁,其实都是通过DexClassLoader来实现的。具体思路是: 创建一个DexClassLoader,通过反射将前者的DexPathList跟系统的PathClassLoader中的DexPathList合并,就可以实现优先加载我们自己的新类,从而替换旧类中的逻辑了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# classloader
# 加载类
# 加载
# 动态加载
# Android源码探究之BaseDexClassLoader的使用
# 关于Android中自定义ClassLoader耗时问题的追查
# 浅谈Android Classloader动态加载分析
# Android开发中类加载器DexClassLoader的简单使用讲解
# Android类加载ClassLoader双亲委托机制详解
# 都是
# 是一个
# 来实现
# 结果是
# 子类
# 自定义
# 自己的
# 几个
# 如果你
# 有两个
# 是在
# 来了
# 那就
# 不太
# 是怎么
# 它是
# 如果没有
# 它可以
# 只需要
相关文章:
建站与域名管理如何高效结合?
,如何利用word制作宣传手册?
建站之星五站合一营销型网站搭建攻略,流量入口全覆盖优化指南
深圳网站制作的公司有哪些,dido官方网站?
建站之星导航菜单设置与功能模块配置全攻略
专业公司网站制作公司,用什么语言做企业网站比较好?
如何通过网站建站时间优化SEO与用户体验?
电影网站制作价格表,那些提供免费电影的网站,他们是怎么盈利的?
红河网站制作公司,红河事业单位身份证如何上传?
建站之星代理如何获取技术支持?
宝塔建站无法访问?如何排查配置与端口问题?
如何快速搭建高效简练网站?
如何快速上传建站程序避免常见错误?
建站主机CVM配置优化、SEO策略与性能提升指南
建站之星如何实现五合一智能建站与营销推广?
已有域名能否直接搭建网站?
建站之星如何实现网站加密操作?
如何用PHP工具快速搭建高效网站?
制作旅游网站html,怎样注册旅游网站?
建站主机选哪种环境更利于SEO优化?
如何通过主机屋免费建站教程十分钟搭建网站?
建站之星如何保障用户数据免受黑客入侵?
阿里云网站搭建费用解析:服务器价格与建站成本优化指南
太原网站制作公司有哪些,网约车营运证查询官网?
如何高效利用亚马逊云主机搭建企业网站?
如何在Golang中使用encoding/gob序列化对象_存储和传输数据
深圳网站制作费用多少钱,读秀,深圳文献港这样的网站很多只提供网上试读,但有些人只要提供试读的文章就能全篇下载,这个是怎么弄的?
制作宣传网站的软件,小红书可以宣传网站吗?
如何在阿里云通过域名搭建网站?
c# Task.Yield 的作用是什么 它和Task.Delay(1)有区别吗
长沙做网站要多少钱,长沙国安网络怎么样?
小米网站链接制作教程,请问miui新增网页链接调用服务有什么用啊?
如何选择PHP开源工具快速搭建网站?
深圳网站制作平台,深圳市做网站好的公司有哪些?
常州自助建站工具推荐:低成本搭建与模板选择技巧
我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?
如何选择美橙互联多站合一建站方案?
如何通过虚拟主机快速搭建个人网站?
如何快速上传自定义模板至建站之星?
*服务器网站为何频现安全漏洞?
如何解决ASP生成WAP建站中文乱码问题?
个人摄影网站制作流程,摄影爱好者都去什么网站?
沈阳个人网站制作公司,哪个网站能考到沈阳事业编招聘的信息?
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
如何在景安服务器上快速搭建个人网站?
如何在企业微信快速生成手机电脑官网?
高防服务器如何保障网站安全无虞?
详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)
建站主机系统SEO优化与智能配置核心关键词操作指南
建站之星如何修改网站生成路径?
*请认真填写需求信息,我们会在24小时内与您取得联系。