编译插桩介绍

概念

编译插桩就是在代码编译期间修改修改已有的代码或者生成新的代码。
编译插桩技术从对代码修改的时机上来说可以分为两种:
Java 文件:在编译最开始的时候介入,动态生成 Java 文件,之后编译器将生成的 Java 文件编译成 class 文件,像 ButterKnife、Dagger 都是通过 这种方式生成代码的。对应的技术主要是APT(Annotation Process Tools

字节码文件:在生成 class 文件后介入,直接修改 class文件的字节码,达到修改代码的目的。常用的字节码编程框架有AspectJJavassistASM

bytecodeprogress.png

什么是字节码?

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$

showbytesetting.png

每次生成字节码之前记得先build/rebuild一下工程,不然会失败
showbytecode.png

简单分析下字节码构成

byte1.png
byte2.png
byte3.png
  • kotlin文件查看方式
showkotlin.png

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 这些第三方的代码检查工具也同样使用的是编译插桩技术实现。

插桩实践

Javassist+gradle transform+annotation 实现方法耗时统计

你可能感兴趣的:(编译插桩介绍)