一、简介
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的
JVMTIAgentinstrument
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-impljar包。
测试结果
agentman 函数测试
无需增加 JVM 参数,直接通过代码的方式运行。
在agent-test项目中的Application#main方法中追加代码:
如果无法引用到VirtualMacineDescriptor,需要手动引入依赖
