引用:
Java成神之路——javaAgent(插桩,attach)
字节码插桩之Java Agent
java探针视频
1.Java agent是什么
javaAgent像是一个动态的类修改器+程序监视器+JVM控制器
javaAgent运行类装载器在JVM装载类之前对类做出动态的修改.
运行java命令执行时添加参数 -javaagent指定打包好的agent的jar即可以. 可以定义多个agent,按指定顺序执行
java -javaagent:agent1.jar -javaagent:agent2.jar -jar MyProgram.jar
字节码插桩,bTrace,Arthas 都是通过这种方式来实现。
javaAgent类方法
创建一个类里面定义agent方法
public static void premain(String agentArgs, Instrumentation inst)
public static void premain(String agentArgs)
- agentArgs 是 premain 函数得到的程序参数,随同 -javaagent一起传入。与 main 函数不同的是,这个参数是一个字符串而不是一个字符串数组,如果程序参数有多个,程序需要自行解析这个字符串。
- Inst 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入,接口中集中了几乎所有的功能方法,例如类定义的转换和操作等等。
JVM 会优先加载 带 Instrumentation 签名的方法,加载成功忽略第二种,如果第一种没有,则加载第二种方法。Instrumentation是一个重要的参数。
2.使用步骤
- 定义一个 MANIFEST.MF 文件,必须包含 Premain-Class 选项,通常也会加入Can-Redefine-Classes 和 Can-Retransform-Classes 选项。
- 创建一个Premain-Class 指定的类,类中包含 premain 方法,方法逻辑由用户自己确定。
- 将 premain 的类和 MANIFEST.MF 文件打成 jar 包。
- 使用参数 -javaagent: jar包路径 启动要代理的方法。
在执行以上步骤后,JVM 会先执行 premain 方法,大部分类加载都会通过该方法,注意:是大部分,不是所有。当然,遗漏的主要是系统类,因为很多系统类先于 agent 执行,而用户类的加载肯定是会被拦截的。也就是说,这个方法是在 main 方法启动前拦截大部分类的加载活动,既然可以拦截类的加载,那么就可以去做重写类这样的操作,结合第三方的字节码编译工具,比如ASM,javassist,cglib等等来改写实现类。
用maven的话可以使用插件自动生成MAINFAST.mf文件。