AOP实践:java.lang.instrument的使用
背景
在 rcjp 项目中,需要调用 ASM API(用于字节码处理的开源库)对字节码进行处理,目标是实现对 Java 程序运行时各种对象的动态跟踪,并进一步分析各个对象之间的关系。在此之前,需要考虑如何获取程序运行的入口。
首先,我考虑到了自定义类加载器(详情见参考资料),即在程序的 main 入口处,首先加载自定义的类加载器,然后通过反射技术使用这个类加载器加载并调用测试程序。这个方法缺点是:每次都必须先找到测试程序的入口类,而对于有的封装成 jar 的程序集合,这一点相对比较难控制。
于是,有了这里介绍的方法:通过 java.lang.instrument 实现的 java agent 对象操作字节码,是一种 AOP 的方法。
程序中,除了 ASMAgent 以外的所有类都是调用 ASM API 实现对测试程序中各个对象的构造、方法调用、属性赋值等操作行为的记录(其中对 Collection 子类的处理着实费了一番心血= =,字节码操作很细节,容易出错)。
原理
JVMTI(Java Virtual Machine Tool Interface)是一套本地编程接口集合,它提供了一套『代理』机制,可以支持第三方工具程序以代理的方式连接和访问 JVM,并利用 JVMTI 提供的丰富的编程接口,完成很多跟 JVM 相关的功能。
java.lang.instrument 包的实现,也就是基于这种机制的:在 Instrumentation 的实现当中,存在一个 JVMTI 的代理程序,通过调用 JVMTI 当中 Java 类相关的函数来完成 Java 类的动态操作。
Instrumentation 的最大作用就是类定义的动态改变和操作。在 Java SE 5 及其后续版本当中,开发者可以在一个普通 Java 程序(带有 main 函数的 Java 类)运行时,通过 – javaagent 参数指定一个特定的 jar 文件(包含 Instrumentation 代理)来启动 Instrumentation 的代理程序。
步骤
1.编写 java 代理类
这个类中,premain 方法是关键,对比于一般的入口 main 一样,这里的 premain 是在 main 之前执行的。它会告诉 JVM 如何处理加载上来的 java 字节码。如下例:
1 |
|
值得注意的是,addTransformer 实现了对字节码处理的方法的回调。
1 |
|
类 ASMAgent 包含着实现对 java 字节码处理的方法:transform()。它来自于 ClassFileTransformer 接口。为了方便,这里将对 ClassFileTransformer 接口的实现跟 ASMAgent 类放在了一起。其中 classfileBuffer 是类文件加载时的原始的字节码,retVal 则是经过处理后的字节码。
1 |
|
2.打包代理类
只有合理打包并在 manifest 文件中记录下相应的键值对之后,才能正常执行 premain 的内容。 manifest 文件中需要添加的键值对是:
1 |
|
如果对字节码的处理有应用到了其他的类,需要在 manifest 中增加路径。比如使用到了 asm-3.0.jar,则增加如下语句:
1 |
|
3.执行
执行测试程序时,添加“-javaagent:代理类的 jar[=传入 premain 的参数]”选项。
比如,对于博主的程序,就是
java
-javaagent:ASMInstrument.jar -jar XXXX.jar xxxx
其中 ASMInstrument.jar 是第二步中打包的程序, XXX.jar 是需要测试的程序, xxx 是 XXX.jar 执行时可能的命令行参数。
如果只是执行某.class 文件中的类,我们假设是在当前目录下的一个 XXXX 类,则是: java
-javaagent:ASMInstrument.jar -cp ./ XXXX xxx
其中 xxx 是可能的命令行参数。
参考资料
原文地址:http://biaobiaoqi.me/blog/2013/09/08/custom-premain-method/
版权声明:自由转载-非商用-非衍生-保持署名| Creative Commons BY-NC-ND 3.0
AOP实践:java.lang.instrument的使用的更多相关文章
- java.lang.instrument 中的premain 实现类的个性化加载(附源代码)
背景 想调用ASM API (用于字节码处理的开源API)对字节码进行处理,目标是实现对java程序运行时各种对象的动态跟踪,并进一步分析各个对象之间的关系(研究前提是目前的UML锁阐释的whole- ...
- java.lang.instrument使用
Java在1.5引入java.lang.instrument,你可以由此实现一个Javaagent,通过此agent来修改类的字节码即改变一个类. 程序启动之时启动代理(pre-main) 通过jav ...
- java.lang.instrument.Instrumentation
java.lang.instrument.Instrumentation 看完文档之后,我们发现这么两个接口:redefineClasses和retransformClasses.一个是重新定义cla ...
- J2SE 1.6 特性:java.lang.instrument
1. import java.lang.instrument.Instrumentation; public class ObjectSizeFetcher { private static Inst ...
- java.lang.instrument: 一个Java对象占用多少字节?
一.对象头包括两部分信息:Mark Word(标记字段)和 Klass Pointer(类型指针) 1. Mark Word 用于存储对象自身的运行时数据,如哈希码(HashCode).GC分代年 ...
- java 编程基础 Class对象 反射:动态代理 和AOP:java.lang.reflect.Proxy:(Proxy.newProxyInstance(newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h))
为什么我们使用动态代理 静态代理会让类变多了,多了代理类,工作量变大了,且不易扩展.比如我们上节课的例子,要实现不同的扩展方法就要编写不同的代理类,非常麻烦. Proxy类的使用规则 Proxy提 ...
- java.lang包
作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 1.特性——不用import 2.String String x = "abc"; < ...
- 转:AOP与JAVA动态代理
原文链接:AOP与JAVA动态代理 1.AOP的各种实现 AOP就是面向切面编程,我们可以从以下几个层面来实现AOP 在编译期修改源代码 在运行期字节码加载前修改字节码 在运行期字节码加载后动态创建代 ...
- AOP与JAVA动态代理
1.AOP的各种实现 AOP就是面向切面编程,我们可以从以下几个层面来实现AOP 在编译期修改源代码 在运行期字节码加载前修改字节码 在运行期字节码加载后动态创建代理类的字节码 2.AOP各种实现机制 ...
- jdk研究——java.lang
jdk研究 volatile 是什么意思? 如何看jdk源码? 如何调试源码!---------仔细解读关键类,关键代码,常用的api的解释! 自己有疑问的不懂地方-------- 不懂的太多怎么办. ...
随机推荐
- ARC119F 题解
前言 ARC119F 好厉害,是没见过的自动机 DP. 正文 [1] 分析 主要分析一下为什么这么写. [2] 状态设计 [3] 自动机状态转移 感觉状态设计中最难的就是如何处理带 \(O\) 的. ...
- Mybatis骚操作-通用查询工具类
老项目大多都有对JDBC进行了封装,可以直接执行SQL的工具类,在做项目升级改造的时候(这里仅指整合mybatis),要么全部调整成dao-xml的形式(会有改动代码多的问题,而且看代码时需要xml和 ...
- Hive 2.3.2安装
一.安装mysql 安装MySQL服务器端和MySQL客户端: •安装: – yum install mysql – yum install mysql-server •启动: – /etc/init ...
- 【赵渝强老师】Kafka的持久化
一.Kafka持久化概述 Kakfa 依赖文件系统来存储和缓存消息.对于硬盘的传统观念是硬盘总是很慢,基于文件系统的架构能否提供优异的性能?实际上硬盘的快慢完全取决于使用方式.同时 Kafka 基于 ...
- Resource Acquisition Is Initialization
在 C++ 中,资源获取即初始化(RAII, Resource Acquisition Is Initialization)是一种管理资源的编程惯用法.其核心思想是将资源的获取和释放绑定到对象的生命周 ...
- 手写 p-map(控制并发数以及迭代处理 promise 的库)
介绍 p-map 是一个迭代处理 promise 并且能控制 promise 执行并发数的库.作者是 sindresorhus,他还创建了许多关于 promise 的库 promise-fun,感兴趣 ...
- BC1.2和PD 充电的区别
USB Battery Charging Specification 1.2(BC1.2)和 USB Power Delivery(USB PD)是两个不同的充电标准,它们在应用场景.充电能力.充电协 ...
- threejs渲染基础的3D场景
// 创建一个场景对象 let scene = new THREE.Scene(); // 创建一个相机对象 let camera = new THREE.PerspectiveCamera(75, ...
- 使用rancher cli对接k8s
一.获得rancher的token 1.进入rancher,点击右上角弹出框的ApI&Keys 2.进入页面后选择添加key 3.注意,这里的作用集群范围必须不能指定,否则在jenkins服务 ...
- HiT-SR:基于层级Transformer的超分辨率,计算高效且能提取长距离关系 | ECCV'24
Transformer在计算机视觉任务中表现出了令人鼓舞的性能,包括图像超分辨率(SR).然而,流行的基于Transformer的SR方法通常采用具有二次计算复杂度的窗口自注意力机制,导致固定的小窗口 ...