简介
java.lang.instrument 包是Java 中来增强JVM 上的应用的一种方式,机制是在JVM 启动前或启动后attach 上去进行修改方法字节码的方式。
instrument 包的用途很多,主要体现在对代码侵入低的优点上。
例如一些监控不方便修改业务代码,但是可以使用这种方式在方法中植入特定逻辑,这种方式能够直接修改JVM 中加载的字节码的内容,而不需要在像Spring AOP 实现中创建新的代理类,所以在底层侵入更高,但是对开发者更透明。
使用方式是通过在启动命令上添加参数的方式添加一个称为agent 的jar 包。
1 | java -javaagent:xxx.jar xx.jar |
用途
- 可以在加载 class 文件之前做拦截,对字节码做修改。
- 可以在运行期对已加载类的字节码做变更,但是这种情况下会有很多的限制。
- 还有其他一些小众的功能:
- 获取所有已经加载过的类。
- 获取所有已经初始化过的类(执行过 clinit 方法,是上面的一个子集)。
- 获取某个对象的大小。
- 将某个 jar 加入到 bootstrap classpath 里作为高优先级被 bootstrapClassloader 加载。
- 将某个 jar 加入到 classpath 里供 AppClassloard 去加载。
- 设置某些 native 方法的前缀,主要在查找 native 方法的时候做规则匹配。
示例:
- 用于自动添加getter/setter方法的工具lombok就使用了这一技术。
- 另外btrace 和housemd 等动态诊断工具也是用了instrument技术。
- 在实现不停机的情况下更新jar 包,即热部署,也是使用了这一技术。
简单实现
创建agent jar 包必须具备的两个特点:
- 创建META-INF/MANEFIST.MD文件,并设置Premain-Class。
- 在创建的类中,实现premain(String agentOps, Instrumentation inst) 函数。
MANIFEST.MF
1 | Manifest-Version: 1.0 |
实现类
GreetingAgent 类:
1 | package cn.vgbhfive; |
测试
测试类:
1 | package cn.vgbhfive; |
结果
1 | // TODO |
实现热部署
Spring 官方的热部署组件就是基于Java Agent 实现的,有兴趣的可以看看。
但是目前还有几个小问题亟待解决。
https://github.com/spring-projects/spring-loaded
引用
https://liuzhengyang.github.io/2017/03/15/javaagent/
https://www.cnkirito.moe/instrument/
个人备注
此博客内容均为作者学习所做笔记,侵删!
若转作其他用途,请注明来源!