概念
编译插桩
就是在代码编译期间修改修改已有的代码或者生成新的代码。
编译插桩技术从对代码修改的时机上来说可以分为两种:
Java 文件
:在编译最开始的时候介入,动态生成 Java 文件,之后编译器将生成的 Java 文件编译成 class 文件,像 ButterKnife、Dagger 都是通过 这种方式生成代码的。对应的技术主要是APT(Annotation Process Tools
字节码文件
:在生成 class 文件后介入,直接修改 class文件的字节码,达到修改代码的目的。常用的字节码编程框架有AspectJ
、Javassist
、ASM
等
什么是字节码?
Java 字节码是Java虚拟机执行的一种指令格式。Java源文件经Java编译器后得到Java字节码(.class)文件。Java字节码(.class)文件可以看作是Java虚拟机的可执行文件。这些字节码(.class)文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)
如何查看字节码
这里拿AndroidStudio举例,所有基于IDEA的IDE应该都一样。
在Settings -> Tools中添加External Tools,输入Name和下面三要素,保存即可
$JDKPath$\bin\javap
-c -verbose $FileClass$
$OutputPath$
每次生成字节码之前记得先
build/rebuild
一下工程,不然会失败showbytecode.png
简单分析下字节码构成
byte1.png byte2.png byte3.png- kotlin文件查看方式
Android字节码编程
在安卓中,编译过程是由gradle task来执行的,Gradle1.5以后提供了transform-api可以在代码转化为.class文件之后再打包成dex文件之前对它进行处理,所以我们可以自定义transform,在appcompileDebugJavaWithJavac这个gradle task之后就会走我们自定义的transform。
使用场景
-
代码生成
。除了 Dagger、ButterKnife 这些常用的注解生成框架,Protocol Buffers、数据库 ORM 框架也都会在编译过程生成代码。代码生成隔离了复杂的内部实现,让开发更加简单高效,而且也减少了手工重复的劳动量,降低了出错的可能性。 -
代码监控
。除了网络监控和耗电监控,我们可以利用编译插桩技术实现各种各样的性能监控。为什么不直接在源码中实现监控功能呢?首先我们不一定有第三方 SDK 的源码,其次某些调用点可能会非常分散,例如想监控代码中所有 new Thread() 调用,通过源码的方式并不那么容易实现。 -
代码修改
。我们在这个场景拥有无限的发挥空间,例如某些第三方 SDK 库没有源码,我们可以给它内部的一个崩溃函数增加 try catch,或者说替换它的图片库等。我们也可以通过代码修改实现无痕埋点。 -
代码分析
。上一期我讲到持续集成,里面的自定义代码检查就可以使用编译插桩技术实现。例如检查代码中的 new Thread() 调用、检查代码中的一些敏感权限使用等。事实上,Findbugs 这些第三方的代码检查工具也同样使用的是编译插桩技术实现。
网友评论