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 插件化】插件化原理 ( 类加载器 )相关推荐

  1. Android进阶:十三、自定义类加载器加载加密类文件

    之前面试的时候有许多面试官问类加载器相关的问题,所以这是一个很重要的知识点.而且对于高级Android研发来讲,懂得更多类加载相关的东西,对开发也会有很多的帮助,比如热更新,类加密等. 其实笔者对类加 ...

  2. 【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  3. Android插件化开发基础之Java类加载器与双亲委派模型

    类加载器 Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需 ...

  4. 58同城Android端-最小插件化框架实战和原理分析

    目录 背景 插件化需要了解的知识 2.1 类加载过程和类加载器 2.2 ClassLoader 的 findClass.findLibrary.findResource 2.3 DexClassLoa ...

  5. java类加载器 架构 设计_类加载器(DexClassLoader)与插件化(动态加载)

    类加载器与插件化解析 2.1 类装载器 DexClassLoader 首先,我们需要了解关于java代码本地import的一些知识: import中所引用的类有两个特点: 1.必须存在于本地,当程序运 ...

  6. 我的Android重构之旅:插件化改造及原理

    点击上方"程序员大咖",选择"置顶公众号" 关键时刻,第一时间送达! 先不说楚枫的这般年纪,能够踏入元武一重说明了什么,最主要的是,楚枫在刚刚踏入核心地带时,明 ...

  7. 滴滴开源Android插件化框架VirtualAPK原理分析

    概述 滴滴出行公司的首个对外开源项目 - VirtualAPK.地址:github.com/didi/Virtua- 滴滴自行研发了这款插件化框架,功能全面.兼容性好,还能够适用于有耦合的业务插件,这 ...

  8. Android插件基础之类加载器学习

    记录学习java 加载器学习所获心得,逐步记录了解java加载器的过程.为了知悉android 插件化的实现原理,从而需要从头了解android加载apk,以及基础的java类加载的加载过程情况,为方 ...

  9. Android应用程序插件化研究之DexClassLoader

    文章首发:[Android应用程序插件化研究之DexClassLoader|大利猫](http://www.liuguangli.win/archives/366) 最近在研究Android应用的插件 ...

最新文章

  1. 2020中国人工智能年度评选报名即将截止!4大类别7大奖项开放申请
  2. c++ 新建一个数组
  3. fork()使用(一)
  4. linux mysql 内存监控_MySQL监控性能的一些方法总结
  5. React学习笔记二 通过柯里化函数实现带参数的事件绑定
  6. 电脑不香吗?我在手机上装Python我图什么?
  7. 为Chrome添加Metro风格的快速拨号
  8. 计算的未来30年:2050大会分享实录
  9. mysql批量插入跟更新_mysql批量插入以及批量更新
  10. 个人简历表格 个人简历word百度云 完整个人简历样本
  11. 数学建模-自来水管道铺设问题
  12. 说到VDI与IDV的分分合合,不会再有比这更清晰的解释了!
  13. 在线生成安卓签名证书
  14. 这10种赚钱方法,用手机就可以做,看看哪种适合你?
  15. 联想微型计算机内存条安装,笔记本怎么加内存条,详细教您联想笔记本怎么加内存条...
  16. pdf怎么转换成jpg或png图片?
  17. 根据经纬度,获取方圆10公里内的数据
  18. 基于bmob后端云小程序开发——口袋吉他
  19. 数学建模——微分方程、差分方程、数理统计
  20. 学生成绩管理(链表)c++

热门文章

  1. 经典排序算法python回顾之一 交换排序
  2. 使用String.format简化代码
  3. 小功告成:ReadIE beta
  4. springboot配置cxf
  5. 【原】高清显示屏原理及设计方案
  6. Java开源数据库管理工具
  7. 小程序文本溢出显示省略号(单行/多行)
  8. 图论数学:矩阵树定理
  9. nginx响应高并发参数配置
  10. mysql系列十、mysql索引结构的实现B+树/B-树原理