JVMTI
什么是JVMTI
JVM Tool Interface
简称JVMTI
是一组对外接口,通过这组接口可以实现,获取虚拟机运行状态、线程分析、监控、调试、覆盖率分析等功能。
JVMTIAgent
什么是JVMTIAgent
为了使用JVMTI
提供的对外接口,一般采用Agent
方式来实现JVMTI
提供的对外接口,JVMTIAgent
类似于c
语言的动态库的概念。
实现方式
在Java1.5
之前实现一个Agent
只能通过原生的c/c++
来实现Agent
,在Java1.5
之后提供了instrument
的agent
,也叫做JPLISAgent(Java Programming Language Instrumentation Services Agent)
专门用于Java
方式。
启动方式
Agent
有两种启动方式
- 第一种是在
jvm
启动的时候,指定agent
程序的位置来启动。 - 另外一种方式是jvm已经在运行了,使用
attach
的方式到目标进程里面。在java1.5
的时候只支持jvm
启动,在java1.6
的时候支持attach
的方式启动,在jvm
的tool.jar
里面提供了工具VirtualMachine
来帮助启动agent
。
Instrument
提供了为Java
编程语言插入代码的服务,Instrumentation
是在方法中添加字节码,以便收集使用的数据,由于这些改变是添加字节码,不会修改程序的状态或者行为。比如监视器代码、探查器、覆盖率分析器和事件记录器。Instrument
只是提供插入代码服务,在方法中添加字节码,至于具体的字节码操作,是由字节码操作工具来实现的,常见的字节码操作工具包括:CGLIB
、Javassist
、ASM
等。获取Instrumentation实例 指定接收类
要获取
Instrumentation
实例,首先要指定将Instrumentation
实例传递给哪个类,有两种方式来指定传递给这个类。- 第一种方式是在配置文件
resource\META_INF\MANIFEST.MF
中指定。
Manifest-Version: 1.0 Can-Redefine-Classes: true Can-Retransform-Classes: true Premain-Class: com.lee.agent.PreMainAgent Agent-Class: com.lee.agent.PreMainAgent
- 【Java Instrument】第二种方式是在
pom
文件中指定,本质上也是在配置MANIFEST.MF
文件
com.lee.agent.PreMainAgent com.lee.agent.PreMainAgent
- 当
JVM
以指定代理类的方式启动,在这种情况下Instrumentation
实例被传给代理类的premain
方法;
public static void premain(String agentArgs, Instrumentation inst); public static void premain(String agentArgs);
- 当
JVM
启动后,以attach
的方式指定代理类,在这种情况下Instrumentation
实例被传递给代理类的agentmain
方法。
public static void agentmain(String agentArgs, Instrumentation inst); public static void agentmain(String agentArgs);
文章图片
目标程序 目标程序是被操作的程序,被修改的是目标类
TargetClass
。public class Demo {
public static void main(String[] args) throws Exception {
TargetClass targetClass = new TargetClass();
targetClass.targetMethod();
}
}
public class TargetClass {
public String targetMethod() {
System.out.println("执行测试方式");
return "return";
}
}
Agent程序
public class PreMainAgent {
/**
* 指定agentjar包启动,Instrument实例会传递给这个方法
*/
public static void premain(String agentArgs, Instrumentation inst){
customLogic(inst);
}
/**
* attach方法启动,Instrument实例会传递给这个方法
*/
public static void agentmain(String agentArgs, Instrumentation inst){
customLogic(inst);
}
private static void customLogic(Instrumentation inst){
inst.addTransformer(new MyClassTransformer(), true);
}
}
class MyClassTransformer implements ClassFileTransformer {@Override
public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
final ClassPool classPool = ClassPool.getDefault();
CtClass clazz;
CtMethod ctMethod;
try {
if ("com/lee/TargetClass".equals(className)){
clazz = classPool.get("com.lee.TargetClass");
ctMethod = clazz.getDeclaredMethod("targetMethod");
ctMethod.insertBefore("System.out.println(\"****************\");
");
byte[] byteCode = clazz.toBytecode();
clazz.detach();
return byteCode;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
启动
- 先将
agent
项目打包成一个jar
包,agent.jar
- 两种启动方式
- 在启动目标程序的时候指定
agent
的位置:-javaagent:jar包路径\Jagent.jar
- 以
attach
方式启动
// project1启动的pid VirtualMachine vm = VirtualMachine.attach("1856"); vm.loadAgent("jar包路径\Jagent.jar");
- 在启动目标程序的时候指定
推荐阅读
- Java常见问题
- java|编程的智慧(转自王垠个人博客)——满满的编程实践经验不看就错过
- 程序员|一份字节跳动面试官给你的Java技术面试指南,跳槽薪资翻倍
- 程序员|java高分面试指南(淘宝java框架)
- IT文章|转 编程的智慧
- 笔记|weblogic之T3反序列化
- rocketmq2
- rocketmq3
- Java|15:00面试,15:09就出来了 ,问的实在是太...