【Android 插件化】插件化原理 ( 类加载器 )
Android 插件化系列文章目录
【Android 插件化】插件化简介 ( 组件化与插件化 )
【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 )
【Android 插件化】插件化原理 ( 类加载器 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 运行应用 | 代码整理 )
文章目录
- Android 插件化系列文章目录
- 一、" 插件化 " 中的 dex 文件
- 二、类加载器分析
- 三、获取类加载器
- 四、双亲委派机制
一、" 插件化 " 中的 dex 文件
现在的大型 Android 项目 , 基本都是 组件化 + 插件化 开发 , 项目架构上都是 组件化 的框架 , 某些修改频繁的 Module 模块 , 设置成 " 插件 " 模块 , 编译成独立的 APK 文件 , 以 " 插件 " 的形式进行部署 , 供 " 宿主 " 模块调用 ;
应用运行时 , 点击启动某个 " 插件 " APK 中的界面 , 首先先 下载对应的 插件 APK 文件 , 将其放在 内置存储区 中 , 然后加载该 APK 文件 , 主要是 类加载器 DEX 文件中的 Class 字节码数据 ;
在上述项目中 , app 模块是 " 宿主 " 模块 , plugin 模块是 " 插件 " 模块 , 二者都是 " Phone & Tablet Module " 类型的应用 ,
plugin 插件模块 , 编译出的 APK 文件如下 , 其 Java 类都封装在 " classes.dex " 文件中 , 在其中可以找到 PluginActivity.class 的字节码文件 ; 找到该模块后 , 可以将其加载到应用中 , 并跳转到该界面中 ;
二、类加载器分析
类加载 是 通过类加载引擎 , 将字节码数据加载到 Java 虚拟机的运行期数据区 中的 Java 虚拟机栈 中 ;
ClassLoader 加载涉及到 双亲委派机制 , Android 中顶级的类加载器 ClassLoader 是 BootClassLoader , 然后其下是 PathClassLoader , PathClassLoader 与 DexClassLoader 基本相同 ;
DexClassLoader 继承了 BaseDexClassLoader , 没有实现任何逻辑 , 只是调用 BaseDexClassLoader 的构造方法进行初始化 ;
public class DexClassLoader extends BaseDexClassLoader {public DexClassLoader(String dexPath, String optimizedDirectory,String librarySearchPath, ClassLoader parent) {super(dexPath, null, librarySearchPath, parent);}
}
源码地址 : /libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java
PathClassLoader 也是继承了 BaseDexClassLoader , 其中定义的构造方法与 DexClassLoader 相同 ;
public class PathClassLoader extends BaseDexClassLoader {public PathClassLoader(String dexPath, ClassLoader parent) {super(dexPath, null, null, parent);}public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {super(dexPath, null, librarySearchPath, parent);}
}
源码地址 : /libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
因此 PathClassLoader 与 DexClassLoader 实现的功能基本相同 , 二者都可以用于加载 Dex 文件 ;
PathClassLoader 是 Google 官方使用的 , DexClassLoader 是提供给开发者使用的 , 使用类加载器时 , 尽量使用 DexClassLoader ;
三、获取类加载器
在 Activity 中调用如下方法 , 获取不同层级的 ClassLoader ;
getClassLoader()
getClassLoader().getParent()
getClassLoader().getParent().getParent()
代码示例 :
package kim.hsl.plugin;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.util.Log;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.i(TAG, "getClassLoader() : " +getClassLoader());Log.i(TAG, "getClassLoader().getParent() : " +getClassLoader().getParent());Log.i(TAG, "getClassLoader().getParent().getParent() : " +getClassLoader().getParent().getParent());}
}
打印结果 :
I/MainActivity: getClassLoader() : dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/kim.hsl.plugin-_uowA-lCCTOuGQrqkuXOeg==/base.apk"],nativeLibraryDirectories=[/data/app/kim.hsl.plugin-_uowA-lCCTOuGQrqkuXOeg==/lib/arm64, /system/lib64]]]
I/MainActivity: getClassLoader().getParent() : java.lang.BootClassLoader@fc7ec45
I/MainActivity: getClassLoader().getParent().getParent() : null
结果分析 :
在 Activity 中直接调用 getClassLoader()
方法获取的是 PathClassLoader ,
调用 getClassLoader().getParent()
方法获取的是 BootClassLoader ;
此外没有更高层级的 ClassLoader , getClassLoader().getParent().getParent()
方法获取的是空 ;
BaseDexClassLoader 的父类是 ClassLoader , ClassLoader 是个抽象类 , 从继承关系上 , 没有涉及到 BootClassLoader ;
在 ClassLoader 中 , 存在一个 ClassLoader parent
字段 , 该字段通过构造方法传入 , getClassLoader().getParent()
方法拿到的不是 ClassLoader , 而是指定的父类引用 ClassLoader parent
字段 ,
public class BaseDexClassLoader extends ClassLoader {}
源码参考 : /libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
public abstract class ClassLoader {// The parent class loader for delegation// Note: VM hardcoded the offset of this field, thus all new fields// must be added *after* it.private final ClassLoader parent;private ClassLoader(Void unused, ClassLoader parent) {this.parent = parent;}
}
源码参考 : /libcore/ojluni/src/main/java/java/lang/ClassLoader.java
四、双亲委派机制
类加载器层级 : 由高到低 : BootClassLoader -> PathClassLoader / DexClassLoader ;
双亲委派机制 :
自定义的类加载器 MyClassLoader 加载一个 Class 类对象 Student , 可以 指定 parent 父类为 PathClassLoader , 该类会 向其上级父类 PathClassLoader 询问该 Student 类对象 是否被加载过 , 如果没有被加载过 ;
则继续向 上级父类 BootClassLoader 询问 Student 类对象 是否被加载过 , 如果被加载过 , 则返回类对象 , 如果没有被加载过 , 则开始委派子类进行加载 ;
BootClassLoader 委派子类 PathClassLoader 进行加载 Student 类对象 , PathClassLoader 就会委派 MyClassLoader 进行加载 , MyClassLoader 发现其没有子类 , 则开始进行类加载 Student 类对象 ;
在 ClassLoader 中的 loadClass 方法中 , 先调用了
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
方法 , 下检查该类是否被加载过 , 如果没有被加载过 , 则先判断父类是否为空 , 如果不为空 , 则调用父类的 loadClass 方法 ,
if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}
父类也调用父类的 loadClass 方法 , 如果调用到最顶层 , 没有父类 , 则开始加载 ;
ClassLoader 类加载相关源码 :
public abstract class ClassLoader {protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{// First, check if the class has already been loadedClass<?> 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;}
}
源码参考 : /libcore/ojluni/src/main/java/java/lang/ClassLoader.java
【Android 插件化】插件化原理 ( 类加载器 )相关推荐
- Android进阶:十三、自定义类加载器加载加密类文件
之前面试的时候有许多面试官问类加载器相关的问题,所以这是一个很重要的知识点.而且对于高级Android研发来讲,懂得更多类加载相关的东西,对开发也会有很多的帮助,比如热更新,类加密等. 其实笔者对类加 ...
- 【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- Android插件化开发基础之Java类加载器与双亲委派模型
类加载器 Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需 ...
- 58同城Android端-最小插件化框架实战和原理分析
目录 背景 插件化需要了解的知识 2.1 类加载过程和类加载器 2.2 ClassLoader 的 findClass.findLibrary.findResource 2.3 DexClassLoa ...
- java类加载器 架构 设计_类加载器(DexClassLoader)与插件化(动态加载)
类加载器与插件化解析 2.1 类装载器 DexClassLoader 首先,我们需要了解关于java代码本地import的一些知识: import中所引用的类有两个特点: 1.必须存在于本地,当程序运 ...
- 我的Android重构之旅:插件化改造及原理
点击上方"程序员大咖",选择"置顶公众号" 关键时刻,第一时间送达! 先不说楚枫的这般年纪,能够踏入元武一重说明了什么,最主要的是,楚枫在刚刚踏入核心地带时,明 ...
- 滴滴开源Android插件化框架VirtualAPK原理分析
概述 滴滴出行公司的首个对外开源项目 - VirtualAPK.地址:github.com/didi/Virtua- 滴滴自行研发了这款插件化框架,功能全面.兼容性好,还能够适用于有耦合的业务插件,这 ...
- Android插件基础之类加载器学习
记录学习java 加载器学习所获心得,逐步记录了解java加载器的过程.为了知悉android 插件化的实现原理,从而需要从头了解android加载apk,以及基础的java类加载的加载过程情况,为方 ...
- Android应用程序插件化研究之DexClassLoader
文章首发:[Android应用程序插件化研究之DexClassLoader|大利猫](http://www.liuguangli.win/archives/366) 最近在研究Android应用的插件 ...
最新文章
- 2020中国人工智能年度评选报名即将截止!4大类别7大奖项开放申请
- c++ 新建一个数组
- fork()使用(一)
- linux mysql 内存监控_MySQL监控性能的一些方法总结
- React学习笔记二 通过柯里化函数实现带参数的事件绑定
- 电脑不香吗?我在手机上装Python我图什么?
- 为Chrome添加Metro风格的快速拨号
- 计算的未来30年:2050大会分享实录
- mysql批量插入跟更新_mysql批量插入以及批量更新
- 个人简历表格 个人简历word百度云 完整个人简历样本
- 数学建模-自来水管道铺设问题
- 说到VDI与IDV的分分合合,不会再有比这更清晰的解释了!
- 在线生成安卓签名证书
- 这10种赚钱方法,用手机就可以做,看看哪种适合你?
- 联想微型计算机内存条安装,笔记本怎么加内存条,详细教您联想笔记本怎么加内存条...
- pdf怎么转换成jpg或png图片?
- 根据经纬度,获取方圆10公里内的数据
- 基于bmob后端云小程序开发——口袋吉他
- 数学建模——微分方程、差分方程、数理统计
- 学生成绩管理(链表)c++