一、简介
1.1、概述
Java Agent 又称为Java 探针
。
Java Agent 于 JDK1.5 引入。
Java Agent 类似于拦截器,主要功能
- 在 Java 虚拟机启动执行 Java 类编译后的字节码前,提前获取到字节码信息,在字节码被执行前修改代码,实现代码增强。
- 在 JVM 运行期间,修改已经加载的字节码信息
其主要的应用场景有
- IDEA 破解
- 热部署
- 链路追踪工具
- 应用监控
- 诊断工具
Java Agent 代码不能独立运行,需要依附于目标程序的 JVM 进程,通过 -javaagent
参数指定。
1.2、相关术语
JVMTI
JVMTI(JVM Tool Interface)
是 JVM 对外提供给用户扩展的接口集合。JVMTI
基于事件驱动,JVM 每执行一定的逻辑就会触发相关事件回调。
JVMTI
回调机制,是实现如:Debugger
、Profiler
、Monitor
、Thread Analyser
的基础
JVMTIAgent
JVMTIAgent 是一个动态库,JVMTI 接口实现,提供了一些常规无法实现的功能,为了和普通动态库区分,一般会实现一个或者多个函数,如:
- Agent_OnLoad函数
如果agent是在启动时加载的,通过JVM参数设置 - Agent_OnAttach函数
如果agent不是在启动时加载的,而是我们先attach到目标进程上,然后给对应的目标进程发送load命令来加载,则在加载过程中会调用Agent_OnAttach函数 -
javaagent/JPLISAgent
javaagent 也是动态库,依赖于instrument的
JVMTIAgent
instrument
instrument
动态库实现,基于JVMTIAgent
。instrument
实现了Agent_onLoad
和Agent_onAttach
两方法。
即,instrument
提供了 启动加载时的字节码增强
通过-javaanget:jar
的方式-
JVM Attach
JVM Attach
是 JVM 提供的一种进程间通信的功能,能让一个进程传命令给另一个进程,并进行一些内部的操作,比如进行线程 dump,那么就需要执行 jstack 进行,然后把 pid 等参数传递给需要 dump 的线程来执行。1.2、原理
Java Agent 类似于拦截器,提供了两种拦截功能
1、在字节码执行前,即
main函数
执行前,执行premain函数
,对字节码信息进行增强2、通过 JVM Attach 实现,在程序运行期间,执行
agentmain函数
对字节码进行修改增强二、简单案例
2.1、项目代码
agent-impl:实现 agent 功能
- agent-test:测试 agent 功能
2.2、agent-test 基础代码
2.3、agent-impl 实现
premain 函数
实现程序运行前的代码增强
其中RuntimeTransformer
实现ClassFileTransformer
的transform
方法,进行代码增强处理。agentmain 函数
实现程序运行期间的代码增强
其中RuntimeTransformer
实现ClassFileTransformer
的transform
方法,进行代码增强处理。RuntimeTransformer 代码增强具体实现
单纯对特定的类进行打印处理,指定agent-test
项目中的SpringApplication
类进行处理。添加 maven 插件,用来指定 Agent 相关类
2.4、测试
premain 函数测试
运行agent-test
测试代码Application#main
指定-javaanget
参数,指定相关的agent-impl
jar包。
测试结果agentman 函数测试
无需增加 JVM 参数,直接通过代码的方式运行。
在agent-test
项目中的Application#main
方法中追加代码:
如果无法引用到VirtualMacineDescriptor
,需要手动引入依赖