怎么在Android中利用ClassLoader对类进行加载
导读:本文共4306字符,通常情况下阅读需要14分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: Java的类加载设计了一套双亲代理的模式,使得用户没法替换系统的核心类,从而让应用更安全。所谓双亲代理就是指,当加载类的时候首先去Bootstrap中加载类,如果没有则去Extension中加载,如果再没有才去AppClassLoader中去加载。从而实现安全和稳定。Java ClassLoaderBootstrapClassLoader引导类加载器 ,用来加载... ...
目录
(为您整理了一些要点),点击可以直达。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中与加载类相关的方法:
也许你不太了解上面几个函数的区别,没关系,我们来看下源码是如何实现的。
所以优先级大概如下:
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。
它的实例化是通过调用 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。
查看VMStack的源码发现 getCallingClassLoader
其实是一个native函数,Android通过底层实现了这个。
底层想必最终也是拿到LoadedApk里面的ClassLoader。
DexClassLoader
它是一个可以用来加载包含dex文件的jar或者apk文件的,但是它可以用来加载非安装的apk。比如加载sdcard上面的,或者NetWork的。
比如现在很流行的插件化/热补丁,其实都是通过DexClassLoader来实现的。具体思路是: 创建一个DexClassLoader,通过反射将前者的DexPathList跟系统的PathClassLoader中的DexPathList合并,就可以实现优先加载我们自己的新类,从而替换旧类中的逻辑了。
怎么在Android中利用ClassLoader对类进行加载的详细内容,希望对您有所帮助,信息来源于网络。