安卓平台的动态加载原理,本质其实还是利用 java 相关知识实现.然而 java 语言中,开发人员能通过程序进行动态操作 class 的,主要是字节码生成和类加载器这两部分的功能.本文中也主要是围绕这两方面的技术,展开在安卓平台上的应用分析.
阅读本文,一起宏观理解安卓插件化,热修复,模块化,AOP,Java 类加载等知识.
动态加载技术分析
一,Java 基础知识
1,虚拟机类的加载剖析
Java 虚拟机把描述类的数据从 Class 文件加载到内存,对数据进行校验,转化解析和初始化,最终形成被虚拟机直接使用的 Java 类型,完成了类的加载机制.
类型的加载,链接和初始化都是在程序运行时期间完成的,虽然会在初次加载耗一定性能,但是正是这个机制为 Java 提供高度的动态扩展灵活性.如可以编写一个面向接口的应用程序,运行时再决定实际的实现类,实现类可以从本地或是网络动态加载.
类从被加载到虚拟机内存到从内存中卸载,完整的生命周期包括:加载(loading),验证(Verification),准备(Preparation),解析(Resolution),初始化(Initialization),使用(Using),和卸载(UnLoading)七个阶段,其中验证,准备,解析统称为连接(Linking). 这里主要分析下加载阶段:
*'加载'是'类加载'* 过程中的一个阶段,主要完成三件事:1)通过类的全限定名来获取定义此类的二进制字节流.2)将这个字节流所代表的静态储存结构转化为方法区的运行时数据结构.3)在内存中生成此类相应 Class 对象,作为方法区这个类的各种数据的访问入口.
虚拟机规定加载一个类在加载阶段需要能 "通过一个类的全限定名获取此类二进制字节流",但是并没有规定要从哪里,怎样获取,例如:
从 ZIP 中读取,如:jar,dex 等.
网络流中获取,如 Applet.
运行时计算生成,如动态代理.
有其他文件生成,数据库中读取等.
...
这样,开发人员就可以通过自定义类加载器(ClassLoader),或是 hook 系统类加载器来控制字节流的获取方式.
类的显式加载(Class.forName)和隐式加载(如:new)两种加载方式,最后都会调用类加载器的 loadClass 方法来完成类的实际加载工作.
类的加载器具有双亲委托模型,该特性保证了 Java 程序的安全性,但是并不是虚拟机强制规定的,我们也可以自定义类加载机制,来破坏这种机制.如安卓插件加载,热修及 OSGI 模块化动态加载中的类加载技术应用.
2,面向切面编程(AOP)
Java 面对对象的语言,平时用的最多的就是 OOP(面对对象编程),然后在很多技术研发中(如安卓动态加载,性能监控,日志等)慢慢的接触到一个新的名次 **"AOP"**,Google 过后,才发现这是一种很特别,很强大,很高级实用的编程方式.百度百科解释如下:
AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型.利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率.
其实 AOP 编程模式已经存在很多年类,并且在 Android 项目开发中也有很多地方的应用,有很多优秀且流行的工具如 APT,AspectJ, Javassist 等,为我们 AOP 开发提供了便利实现.
不同的工具库作用在不同的阶段,这里引用网络上一张图,可以说明三者间的区别.
APT
APT(Annotation Processing Too)应该都听过并且用过,概念比较好理解,主要作用在编译期,也是比较流行且常见的技术.
代码编译期解析注解后,结合 square 公司的开源项目 javapoet 项目,生成自定逻辑的 java 源码.有很多开源库都在用如:ButterKnife,EventBus 等.
AspectJ
AspectJ 支持编译期和加载时代码注入, 有一个专门的编译器用来生成遵守 Java 字节编码规范的 Class 文件.更多细节可以看 这里 .
Javassist
Javassist 是一个开源的分析,编辑和创建 Java 字节码的类库.允许开发者自由的在一个已经编译好的类中添加新的方法,或者是修改已有的方法,允许开发者忽略被修改的类本身的细节和结构.
360 开源插件项目 RePlugin 中,为了减少对安卓系统的 Hook 点,又希望解耦开发层代码逻辑,其中就用到了 Javassist 技术.
二,插件化技术分析
安卓项目发展早起,可能最初只是为了解决 65535 问题及包大小,各家公司都在研究安卓平台动态加载,也就是现在所谓的插件化解决方案.
从 14 年的 Dynamic-load-apk 开源项目,到现在(17 年)的 RePlugin 及 VirtualAPK,分析下实现原理,个人理解,其实并不是很难,无非就是利用静态代理,动态代理,反射,HOOK 及 ClassLoader(dex 合并,或双亲委托破坏)等相关技术对安卓四大组件的沙盒实现.
当然真正的难点在于对千万安卓机型及 Rom 的适配,及完整安卓功能的兼容实现,不可否认插件化大牛在安卓行业发展的巨大贡献(感谢各位开源大佬
来源: https://juejin.im/post/5a533c8df265da3e236651f3