Java字节码增强技术介绍
作者|田西西
本篇文章主要介绍 java instrument和 ASM,文中部分内容来自Java API doc和 ASM user guide。有兴趣深入研究的同学可以从这两份资料获取更详细的内容。关于工具的具体使用场景和落地,后续会有文章逐步展开,欢迎大家持续关注。
下图是Jacoco代码覆盖率报告。Jacoco如何感知每行代码的执行情况?
下图左侧是从jvm中dump开启Jacoco的代码,右侧为未开启Jacoco,源码为上图中代码:
从图中代码可看出,左侧class多了Jacoco的探针代码。那么Jacoco是如何在程序启动时加入探针的?(Jacoco使用的on-the-fly插桩模式)
类似的还有无源码侵入监控工具、线上热修复功能,是如何在程序启动时或者程序启动后改变原有的代码逻辑?
Java instrument
1、Java instrument介绍
Java.lang.instrument包提供通过 Java代理检测运行在 JVM 上程序的服务。检测机制是对方法的字节码进行修改。Java代理通过jar文件进行部署,可在通过命令行在启动程序的时候加载代理,也可以在JVM启动后加载代理。后续主要介绍通过命令行方式启动。
2、通过命令行启动代理
-javaagent: jarpath[ = options] 将此段命令添加至命令行以启动代理。jarpath 是代理jar文件路径,options是参数(非必须),此段代码可以同时使用多次以启动多个代理。
3、代理jar的组成
1)premain方法
/**
*高优先级
*/
public static void premain(String agentArgs, Instrumentation inst);
/**
*优先级低,如果代理类没有高优先级方法才会调用当前方法
*/
public static void premain(String agentArgs);
agentArgs为命令行中options的内容,代理中通过agentArgs获取options中的内容来获取配置信息,并根据配置的内容执行配置对应的逻辑。
2)Manifest 文件
1、方法
通过实现ClassFileTransformer接口实现类文件转换,通过实现ClassFileTransformer接口的transform方法转换类并返回一个新类,转换器通过Instrumentation的addTransformer方法注册,如果不转换则transform方法返回null
transform方法参数:
2、字节码编辑工具
ASM是一个java字节码编辑工具,它可以用来修改现有的类也可以直接以二进制形式动态生成类。Jacoco覆盖率分析就是通过ASM进行插桩。另外还有一些mock工具如Mockito
3、例子
1)修改class version
code
时序图
2)在method头部及结尾处添加代码
3)ASM Bytecode Viewer
Intellij插件ASM Bytecode Viewer可以查看class的bytecode和ASMified code
Java code
Byte code
ASMified
ASM访问代码时序图
可以在程序启时插入hook代码做到在无源码侵入的情况下加入新功能例如:
性能监控
埋点
热修复
故障注入
mock